Codebase list suricata / c53267b
Imported Upstream version 1.0.2 Pierre Chifflier 13 years ago
52 changed file(s) with 7798 addition(s) and 382 deletion(s). Raw diff Collapse all Expand all
29132913
29142914 # Define the identity of the package.
29152915 PACKAGE=suricata
2916 VERSION=1.0.1
2916 VERSION=1.0.2
29172917
29182918
29192919 cat >>confdefs.h <<_ACEOF
22 AC_INIT(configure.in)
33
44 AM_CONFIG_HEADER(config.h)
5 AM_INIT_AUTOMAKE(suricata, 1.0.1)
5 AM_INIT_AUTOMAKE(suricata, 1.0.2)
66
77 AC_LANG_C
88 AC_PROG_CC_C99
114114 detect-http-header.c detect-http-header.h \
115115 detect-http-uri.c detect-http-uri.h \
116116 detect-tls-version.c detect-tls-version.h \
117 detect-ssh-proto-version.c detect-ssh-proto-version.h \
118 detect-ssh-software-version.c detect-ssh-software-version.h \
117119 detect-icmp-id.c detect-icmp-id.h \
118120 detect-icmp-seq.c detect-icmp-seq.h \
119121 detect-dce-iface.c detect-dce-iface.h \
205207 app-layer-dcerpc-udp.c app-layer-dcerpc-udp.h \
206208 app-layer-ftp.c app-layer-ftp.h \
207209 app-layer-ssl.c app-layer-ssl.h \
210 app-layer-ssh.c app-layer-ssh.h \
208211 defrag.c defrag.h \
209212 output.c output.h \
210213 win32-misc.c win32-misc.h \
105105 detect-icode.$(OBJEXT) detect-http-cookie.$(OBJEXT) \
106106 detect-http-method.$(OBJEXT) detect-http-header.$(OBJEXT) \
107107 detect-http-uri.$(OBJEXT) detect-tls-version.$(OBJEXT) \
108 detect-icmp-id.$(OBJEXT) detect-icmp-seq.$(OBJEXT) \
109 detect-dce-iface.$(OBJEXT) detect-dce-opnum.$(OBJEXT) \
110 detect-dce-stub-data.$(OBJEXT) detect-urilen.$(OBJEXT) \
111 detect-detection-filter.$(OBJEXT) \
108 detect-ssh-proto-version.$(OBJEXT) \
109 detect-ssh-software-version.$(OBJEXT) detect-icmp-id.$(OBJEXT) \
110 detect-icmp-seq.$(OBJEXT) detect-dce-iface.$(OBJEXT) \
111 detect-dce-opnum.$(OBJEXT) detect-dce-stub-data.$(OBJEXT) \
112 detect-urilen.$(OBJEXT) detect-detection-filter.$(OBJEXT) \
112113 detect-http-client-body.$(OBJEXT) detect-asn1.$(OBJEXT) \
113114 util-print.$(OBJEXT) util-fmemopen.$(OBJEXT) \
114115 util-cpu.$(OBJEXT) util-pidfile.$(OBJEXT) util-mpm.$(OBJEXT) \
148149 app-layer-tls.$(OBJEXT) app-layer-smb.$(OBJEXT) \
149150 app-layer-smb2.$(OBJEXT) app-layer-dcerpc.$(OBJEXT) \
150151 app-layer-dcerpc-udp.$(OBJEXT) app-layer-ftp.$(OBJEXT) \
151 app-layer-ssl.$(OBJEXT) defrag.$(OBJEXT) output.$(OBJEXT) \
152 win32-misc.$(OBJEXT) win32-service.$(OBJEXT) \
153 util-action.$(OBJEXT) util-profiling.$(OBJEXT) \
154 cuda-packet-batcher.$(OBJEXT)
152 app-layer-ssl.$(OBJEXT) app-layer-ssh.$(OBJEXT) \
153 defrag.$(OBJEXT) output.$(OBJEXT) win32-misc.$(OBJEXT) \
154 win32-service.$(OBJEXT) util-action.$(OBJEXT) \
155 util-profiling.$(OBJEXT) cuda-packet-batcher.$(OBJEXT)
155156 suricata_OBJECTS = $(am_suricata_OBJECTS)
156157 @BUILD_LIBHTP_TRUE@suricata_DEPENDENCIES = \
157158 @BUILD_LIBHTP_TRUE@ $(top_builddir)/libhtp/htp/libhtp.la
417418 detect-http-header.c detect-http-header.h \
418419 detect-http-uri.c detect-http-uri.h \
419420 detect-tls-version.c detect-tls-version.h \
421 detect-ssh-proto-version.c detect-ssh-proto-version.h \
422 detect-ssh-software-version.c detect-ssh-software-version.h \
420423 detect-icmp-id.c detect-icmp-id.h \
421424 detect-icmp-seq.c detect-icmp-seq.h \
422425 detect-dce-iface.c detect-dce-iface.h \
508511 app-layer-dcerpc-udp.c app-layer-dcerpc-udp.h \
509512 app-layer-ftp.c app-layer-ftp.h \
510513 app-layer-ssl.c app-layer-ssl.h \
514 app-layer-ssh.c app-layer-ssh.h \
511515 defrag.c defrag.h \
512516 output.c output.h \
513517 win32-misc.c win32-misc.h \
625629 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-parser.Po@am__quote@
626630 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-smb.Po@am__quote@
627631 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-smb2.Po@am__quote@
632 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-ssh.Po@am__quote@
628633 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-ssl.Po@am__quote@
629634 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer-tls.Po@am__quote@
630635 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-layer.Po@am__quote@
720725 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-sameip.Po@am__quote@
721726 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-seq.Po@am__quote@
722727 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-sid.Po@am__quote@
728 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-ssh-proto-version.Po@am__quote@
729 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-ssh-software-version.Po@am__quote@
723730 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-stream_size.Po@am__quote@
724731 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-tag.Po@am__quote@
725732 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/detect-threshold.Po@am__quote@
104104 * \param ctx the contex
105105 * \param co the content match
106106 * \param proto the proto id
107 * \initonly
107108 */
108109 static void AlpProtoAddSignature(AlpProtoDetectCtx *ctx, DetectContentData *co, uint16_t ip_proto, uint16_t proto) {
109110 AlpProtoSignature *s = SCMalloc(sizeof(AlpProtoSignature));
110111 if (s == NULL) {
111 return;
112 SCLogError(SC_ERR_FATAL, "Error allocating memory. Signature not loaded. Not enough memory so.. exiting..");
113 exit(EXIT_FAILURE);
112114 }
113115 memset(s, 0x00, sizeof(AlpProtoSignature));
114116
6464 char inputlower[5];
6565
6666 if (input_len >= 4) {
67 memcpy(inputlower,input,5);
67 memcpy(inputlower,input,4);
6868 int i = 0;
6969 for (; i < 4; i++)
7070 inputlower[i] = tolower(inputlower[i]);
7272 if (memcmp(inputlower, "port", 4) == 0) {
7373 fstate->command = FTP_COMMAND_PORT;
7474 }
75
7576 /* else {
7677 * Add the ftp commands you need here
7778 * }
4343 #include "app-layer-htp.h"
4444
4545 #include "util-spm.h"
46 #include "util-unittest.h"
4746 #include "util-debug.h"
4847 #include "app-layer-htp.h"
4948 #include "util-time.h"
5049 #include <htp/htp.h>
50
51 #include "util-unittest.h"
52 #include "util-unittest-helper.h"
53 #include "flow-util.h"
54
55 #include "detect-engine.h"
56 #include "detect-engine-state.h"
57 #include "detect-parse.h"
5158
5259 #include "conf.h"
5360
145152
146153 memset(s, 0x00, sizeof(HtpState));
147154
148 s->body.nchunks = 0;
149 s->body.operation = HTP_BODY_NONE;
150 s->body.pcre_flags = HTP_PCRE_NONE;
151
152155 #ifdef DEBUG
153156 SCMutexLock(&htp_state_mem_lock);
154157 htp_state_memcnt++;
175178
176179 HtpState *s = (HtpState *)state;
177180
181 /* Unset the body inspection */
182 s->flags &=~ HTP_FLAG_NEW_BODY_SET;
183
178184 /* free the connection parser memory used by HTP library */
179 if (s != NULL) {
180 if (s->connp != NULL) {
181 htp_connp_destroy_all(s->connp);
182 }
185 if (s != NULL && s->connp != NULL) {
186 size_t i;
183187 /* free the list of body chunks */
184 if (s->body.nchunks > 0) {
185 HtpBodyFree(&s->body);
186 }
188 if (s->connp->conn != NULL) {
189 for (i = 0; i < list_size(s->connp->conn->transactions); i++) {
190 htp_tx_t *tx = (htp_tx_t *)list_get(s->connp->conn->transactions, i);
191 if (tx != NULL) {
192 SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(tx);
193 if (htud != NULL) {
194 HtpBodyFree(&htud->body);
195 SCFree(htud);
196 }
197 htp_tx_set_user_data(tx, NULL);
198 }
199 }
200 }
201 htp_connp_destroy_all(s->connp);
187202 }
188203
189204 SCFree(s);
243258 /**
244259 * \brief Sets a flag that informs the HTP app layer that some module in the
245260 * engine needs the http request body data.
261 * \initonly
246262 */
247263 void AppLayerHtpEnableRequestBodyCallback(void)
248264 {
668684 "%"PRIu32"", hstate, d, d->data, (uint32_t)d->len);
669685
670686 //PrintRawDataFp(stdout, d->data, d->len);
671
672 /* If it has been inspected by pcre and there's no match,
673 * remove this chunks */
674 if ( !(hstate->body.pcre_flags & HTP_PCRE_HAS_MATCH) &&
675 (hstate->body.pcre_flags & HTP_PCRE_DONE))
676 {
677 HtpBodyFree(&hstate->body);
678 }
679
680 /* If its a new operation, remove the old data */
681 if (hstate->body.operation == HTP_BODY_RESPONSE) {
682 HtpBodyFree(&hstate->body);
683 hstate->body.pcre_flags = HTP_PCRE_NONE;
684 }
685 hstate->body.operation = HTP_BODY_REQUEST;
686
687
688 HtpBodyAppendChunk(&hstate->body, (uint8_t*)d->data, (uint32_t)d->len);
689 hstate->body.pcre_flags = HTP_PCRE_NONE;
687 SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(d->tx);
688 if (htud == NULL) {
689 htud = SCMalloc(sizeof(SCHtpTxUserData));
690 if (htud == NULL) {
691 SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
692 SCReturnInt(HOOK_OK);
693 }
694 memset(htud, 0, sizeof(SCHtpTxUserData));
695 htud->body.operation = HTP_BODY_NONE;
696 htud->body.pcre_flags = HTP_PCRE_NONE;
697
698 /* Set the user data for handling body chunks on this transaction */
699 htp_tx_set_user_data(d->tx, htud);
700 }
701
702 htud->body.operation = HTP_BODY_REQUEST;
703
704 HtpBodyAppendChunk(&htud->body, (uint8_t*)d->data, (uint32_t)d->len);
705 htud->body.pcre_flags = HTP_PCRE_NONE;
690706 if (SCLogDebugEnabled()) {
691 HtpBodyPrint(&hstate->body);
707 HtpBodyPrint(&htud->body);
692708 }
693709
694710 /* set the new chunk flag */
765781 SCReturnInt(HOOK_ERROR);
766782 }
767783
768 /* Free data when we have a response */
769 if (hstate->body.nchunks > 0)
770 HtpBodyFree(&hstate->body);
771
772 hstate->body.operation = HTP_BODY_RESPONSE;
773 hstate->body.pcre_flags = HTP_PCRE_NONE;
784 /* Unset the body inspection (if any) */
785 hstate->flags &=~ HTP_FLAG_NEW_BODY_SET;
774786
775787 /* remove obsolete transactions */
776788 size_t idx;
778790 htp_tx_t *tx = list_get(hstate->connp->conn->transactions, idx);
779791 if (tx == NULL)
780792 continue;
793
794 /* This will remove obsolete body chunks */
795 SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(tx);
796 if (htud != NULL) {
797 HtpBodyFree(&htud->body);
798 htp_tx_set_user_data(tx, NULL);
799 SCFree(htud);
800 }
781801
782802 htp_tx_destroy(tx);
783803 }
18061826 {
18071827 int result = 1;
18081828 Flow f;
1829 FLOW_INITIALIZE(&f);
18091830 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
18101831 " Data is c0oL!";
18111832 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
19071928 StreamTcpFreeConfig(TRUE);
19081929 if (htp_state != NULL)
19091930 HTPStateFree(htp_state);
1931 FLOW_DESTROY(&f);
19101932 return result;
19111933 }
1934
19121935 #endif /* UNITTESTS */
19131936
19141937 /**
8181 any pcre (so we can free() without waiting) */
8282 } HtpBody;
8383
84 /** Now the Body Chunks will be stored per transaction, at
85 * the tx user data */
86 typedef struct SCHtpTxUserData_ {
87 HtpBody body; /**< Body of the request (if any) */
88 } SCHtpTxUserData;
89
8490 typedef struct HtpState_ {
8591
8692 htp_connp_t *connp; /**< Connection parser structure for
8793 each connection */
88 HtpBody body; /**< Body of the request (if any) */
8994 // size_t new_in_tx_index; /**< Index to indicate that after this we have
9095 // new requests to log */
9196 uint8_t flags;
0 /* Copyright (C) 2007-2010 Open Information Security Foundation
1 *
2 * You can copy, redistribute or modify this Program under the terms of
3 * the GNU General Public License version 2 as published by the Free
4 * Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * version 2 along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
14 * 02110-1301, USA.
15 */
16
17 /**
18 * \file
19 *
20 * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
21 *
22 * App-layer parser for SSH protocol
23 *
24 */
25
26 #include "suricata-common.h"
27 #include "debug.h"
28 #include "decode.h"
29 #include "threads.h"
30
31 #include "util-print.h"
32 #include "util-pool.h"
33
34 #include "stream-tcp-private.h"
35 #include "stream-tcp-reassemble.h"
36 #include "stream-tcp.h"
37 #include "stream.h"
38
39 #include "app-layer-protos.h"
40 #include "app-layer-parser.h"
41 #include "app-layer-ssh.h"
42
43 #include "conf.h"
44
45 #include "util-spm.h"
46 #include "util-unittest.h"
47 #include "util-debug.h"
48 #include "flow-private.h"
49
50 #include "util-byte.h"
51
52 /**
53 * \brief Function to parse the SSH version string of the server
54 *
55 * \param ssh_state Pointer the state in which the value to be stored
56 * \param pstate Application layer tarser state for this session
57 * \param input Pointer the received input data
58 * \param input_len Length in bytes of the received data
59 * \param output Pointer to the list of parsed output elements
60 */
61 static int SSHParseServerVersion(Flow *f, void *ssh_state, AppLayerParserState *pstate,
62 uint8_t *input, uint32_t input_len,
63 AppLayerParserResult *output) {
64 uint8_t *line_ptr = input;
65 uint32_t line_len = input_len;
66 uint32_t offset = 0;
67
68 SshState *state = (SshState *)ssh_state;
69
70 while (input_len > 0) {
71 offset = 0;
72
73 if (pstate->store_len > 0){
74 const uint8_t delim[] = { 0x0a, };
75 int r = AlpParseFieldByDelimiter(output, pstate,
76 SSH_FIELD_SERVER_VER_STATE_LINE, delim, sizeof(delim),
77 input, input_len, &offset);
78
79 if (r == 0)
80 SCReturnInt(0);
81
82 /* process the result elements */
83 AppLayerParserResultElmt *e = output->head;
84 line_ptr = NULL;
85 line_len = 0;
86 for (; e != NULL; e = e->next) {
87 SCLogDebug("e %p e->name_idx %" PRIu32 ", e->data_ptr %p, e->data_len "
88 "%" PRIu32, e, e->name_idx,
89 e->data_ptr, e->data_len);
90
91 /* no parser defined for this field. */
92 if (e->name_idx != SSH_FIELD_SERVER_VER_STATE_LINE) {
93 continue;
94 }
95
96 line_ptr = e->data_ptr;
97 line_len = e->data_len;
98 }
99
100 /* Update for the next round */
101 input_len -= offset;
102 input += offset;
103
104 if (line_ptr == NULL)
105 continue;
106 } else {
107 const uint8_t delim[] = { 0x0a, };
108 int r = AlpParseFieldByDelimiter(output, pstate,
109 SSH_FIELD_SERVER_VER_STATE_LINE, delim, sizeof(delim),
110 input, input_len, &offset);
111
112 if (r == 0)
113 SCReturnInt(0);
114
115 /* Temporal pointer / len for the current line */
116 line_ptr = input;
117 line_len = offset;
118
119 /* Update for the next round */
120 input_len -= offset;
121 input += offset;
122 }
123
124 //printf("INPUT: \n");
125 //PrintRawDataFp(stdout, line_ptr, line_len);
126
127 if (line_len < 5) {
128 SCLogDebug("This is not the version line we are searching for (probably a banner or informational messages)");
129 continue;
130 }
131
132 /* is it the version line? */
133 if (memcmp("SSH-", line_ptr, 4) == 0) {
134 if (line_len > 255) {
135 SCLogDebug("Invalid version string, it should be less than 255 characters including <CR><NL>");
136 SCReturnInt(-1);
137 }
138
139 /* ok, we have found the version line/string, skip it and parse proto version */
140 line_ptr += 4;
141 line_len -= 4;
142 } else {
143 SCLogDebug("This is not the version line we are searching for (probably a banner or informational messages)");
144 continue;
145 }
146
147 uint8_t *proto_end = BasicSearch(line_ptr, line_len, (uint8_t*)"-", 1);
148 if (proto_end == NULL) {
149 /* Strings starting with SSH- are not allowed
150 * if they are not the real version string */
151 SCLogDebug("Invalid Version String for SSH (invalid usage of SSH- prefix)");
152 SCReturnInt(-1);
153 }
154
155 uint64_t proto_ver_len = (uint64_t)(proto_end - line_ptr);
156 state->server_proto_version = SCMalloc(proto_ver_len + 1);
157 if (state->server_proto_version == NULL) {
158 SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
159 SCReturnInt(-1);
160 }
161 memcpy(state->server_proto_version, line_ptr, proto_ver_len);
162 state->server_proto_version[proto_ver_len] = '\0';
163
164 /* Now lets parse the software & version */
165 line_ptr += proto_ver_len + 1;
166 line_len -= proto_ver_len + 1;
167 if (line_len < 1) {
168 SCLogDebug("No software version specified (weird)");
169 state->flags |= SSH_FLAG_CLIENT_VERSION_PARSED;
170 /* Return the remaining length */
171 SCReturnInt(input_len);
172 }
173
174 uint8_t *sw_end = BasicSearch(line_ptr, line_len, (uint8_t*)" ", 1);
175 if (sw_end == NULL) {
176 sw_end = BasicSearch(line_ptr, line_len, (uint8_t*)"\r", 1);
177 if (sw_end == NULL) {
178 sw_end = line_ptr + line_len;
179 }
180 }
181
182 uint64_t sw_ver_len = (uint64_t)(sw_end - line_ptr);
183 state->server_software_version = SCMalloc(sw_ver_len + 1);
184 if (state->server_software_version == NULL) {
185 SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
186 SCReturnInt(-1);
187 }
188 memcpy(state->server_software_version, line_ptr, sw_ver_len);
189 state->server_software_version[sw_ver_len] = '\0';
190 if (state->server_software_version[sw_ver_len - 1] == 0x0d)
191 state->server_software_version[sw_ver_len - 1] = '\0';
192
193 state->flags |= SSH_FLAG_SERVER_VERSION_PARSED;
194 /* Return the remaining length */
195 SCReturnInt(input_len);
196 }
197
198 SCReturnInt(0);
199 }
200
201 /**
202 * \brief Function to parse the SSH field in packet received from the server
203 *
204 * \param ssh_state Pointer the state in which the value to be stored
205 * \param pstate Application layer tarser state for this session
206 * \param input Pointer the received input data
207 * \param input_len Length in bytes of the received data
208 * \param output Pointer to the list of parsed output elements
209 */
210 static int SSHParseServerRecord(Flow *f, void *ssh_state, AppLayerParserState *pstate,
211 uint8_t *input, uint32_t input_len,
212 AppLayerParserResult *output)
213 {
214 SshState *state = (SshState *)ssh_state;
215 if (state->flags & SSH_FLAG_PARSER_DONE) {
216 SCReturnInt(0);
217 }
218
219 SCEnter();
220 int ret = 0;
221
222 SCLogDebug("ssh_state %p, pstate %p, input %p,input_len %" PRIu32 "",
223 ssh_state, pstate, input, input_len);
224 //PrintRawDataFp(stdout, input,input_len);
225
226 if (pstate == NULL)
227 SCReturnInt(-1);
228
229 if ( !(state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) {
230 ret = SSHParseServerVersion(f, ssh_state, pstate, input, input_len, output);
231 if (ret < 0) {
232 if (ret <= -1) {
233 SCLogDebug("Invalid version string");
234 SCReturnInt(-1);
235 }
236 SCLogDebug("Version string not parsed yet");
237 pstate->parse_field = 0;
238 SCReturnInt(ret);
239 } else if (state->flags & SSH_FLAG_SERVER_VERSION_PARSED) {
240 SCLogDebug("Version string parsed");
241 input += input_len - ret;
242 input_len -= (input_len - ret);
243 pstate->parse_field = 1;
244 ret = 1;
245 if (input_len == 0)
246 SCReturnInt(ret);
247 } else {
248 SCLogDebug("Version string not parsed yet");
249 pstate->parse_field = 0;
250 SCReturnInt(ret);
251 }
252 } else {
253 SCLogDebug("Version string already parsed");
254 }
255
256 uint16_t max_fields = 4;
257 int16_t u = 0;
258 uint32_t offset = 0;
259
260 //PrintRawDataFp(stdout, input,input_len);
261
262 if (pstate == NULL)
263 SCReturnInt(-1);
264
265 for (u = pstate->parse_field; u < max_fields; u++) {
266 SCLogDebug("u %" PRIu32 "", u);
267
268 switch(u % 4) {
269 case 0:
270 {
271 continue;
272 }
273 case 1: /* TLS CONTENT TYPE */
274 {
275 uint8_t *data = input + offset;
276 uint32_t data_len = input_len - offset;
277
278 int r = AlpParseFieldBySize(output, pstate,
279 SSH_FIELD_SERVER_PKT_LENGTH,
280 /* single byte field */4, data,
281 data_len, &offset);
282 SCLogDebug("r = %" PRId32 "", r);
283
284 if (r == 0) {
285 pstate->parse_field = 1;
286 SCReturnInt(0);
287 } else if (r == -1) {
288 SCLogError(SC_ERR_ALPARSER, "AlpParseFieldBySize failed, "
289 "r %d", r);
290 SCReturnInt(-1);
291 }
292
293 uint32_t pkt_len = 0;
294 int ret = ByteExtractUint32(&pkt_len, BYTE_BIG_ENDIAN,
295 output->tail->data_len, output->tail->data_ptr);
296 if (ret != 4) {
297 SCReturnInt(-1);
298 }
299 state->srv_hdr.pkt_len = pkt_len;
300 SCLogDebug("pkt len: %"PRIu32, pkt_len);
301
302 break;
303 }
304 case 2: /* TLS VERSION */
305 {
306 uint8_t *data = input + offset;
307 uint32_t data_len = input_len - offset;
308
309 int r = AlpParseFieldBySize(output, pstate,
310 SSH_FIELD_SERVER_PADDING_LENGTH,
311 /* 2 byte field */1, data, data_len,
312 &offset);
313 if (r == 0) {
314 pstate->parse_field = 2;
315 SCReturnInt(0);
316 } else if (r == -1) {
317 SCLogError(SC_ERR_ALPARSER, "AlpParseFieldBySize failed, "
318 "r %d", r);
319 SCReturnInt(-1);
320 }
321 uint8_t padding_len = 0;
322 if (output->tail->data_len == 1) {
323 padding_len = (uint8_t) *output->tail->data_ptr;
324 SCLogDebug("padding len: %"PRIu8, padding_len);
325 }
326 state->srv_hdr.padding_len = padding_len;
327
328 break;
329 }
330 case 3: /* SSH_PAYLOAD */
331 {
332 uint8_t *data = input + offset;
333 uint32_t data_len = input_len - offset;
334
335 /* we add a -1 to the pkt len since the padding length is already parsed */
336 int r = AlpParseFieldBySize(output, pstate, SSH_FIELD_SERVER_PAYLOAD,
337 state->srv_hdr.pkt_len - 1, data, data_len,
338 &offset);
339 SCLogDebug("AlpParseFieldBySize returned r %d, offset %"PRIu32,
340 r, offset);
341 if (r == 0) {
342 pstate->parse_field = 3;
343 SCReturnInt(0);
344 } else if (r == -1) {
345 SCLogError(SC_ERR_ALPARSER, "AlpParseFieldBySize failed, "
346 "r %d", r);
347 SCReturnInt(-1);
348 }
349
350 uint8_t msg_code = 0;
351 if (output->tail->data_len >= 1) {
352 msg_code = (uint8_t) *output->tail->data_ptr;
353 SCLogDebug("msg code: %"PRIu8, msg_code);
354 }
355 state->srv_hdr.msg_code = msg_code;
356
357 if (state->srv_hdr.msg_code == SSH_MSG_NEWKEYS) {
358 /* We are not going to inspect any packet more
359 * as the data is now encrypted */
360 SCLogDebug("SSH parser done (the rest of the communication is encrypted)");
361 state->flags |= SSH_FLAG_PARSER_DONE;
362 pstate->flags |= APP_LAYER_PARSER_DONE;
363 pstate->flags |= APP_LAYER_PARSER_NO_INSPECTION;
364 pstate->flags |= APP_LAYER_PARSER_NO_REASSEMBLY;
365 pstate->parse_field = 1;
366 SCReturnInt(1);
367 }
368
369 pstate->parse_field = 1;
370 ret = 1;
371
372 /* If we have remaining data, continue processing */
373 if ((int)input_len - (int)offset > 0) {
374 u = 0;
375 }
376 break;
377 }
378 }
379
380 }
381
382 SCReturnInt(ret);
383 }
384
385 /**
386 * \brief Function to parse the SSH version string of the client
387 *
388 * \param ssh_state Pointer the state in which the value to be stored
389 * \param pstate Application layer tarser state for this session
390 * \param input Pointer the received input data
391 * \param input_len Length in bytes of the received data
392 * \param output Pointer to the list of parsed output elements
393 */
394 static int SSHParseClientVersion(Flow *f, void *ssh_state, AppLayerParserState *pstate,
395 uint8_t *input, uint32_t input_len,
396 AppLayerParserResult *output) {
397 uint8_t *line_ptr = input;
398 uint32_t line_len = input_len;
399 uint32_t offset = 0;
400
401 SshState *state = (SshState *)ssh_state;
402
403 while (input_len > 0) {
404 offset = 0;
405
406
407 if (pstate->store_len > 0){
408 const uint8_t delim[] = { 0x0a, };
409 int r = AlpParseFieldByDelimiter(output, pstate,
410 SSH_FIELD_CLIENT_VER_STATE_LINE, delim, sizeof(delim),
411 input, input_len, &offset);
412
413 if (r == 0)
414 SCReturnInt(0);
415
416 /* process the result elements */
417 AppLayerParserResultElmt *e = output->head;
418 line_ptr = NULL;
419 line_len = 0;
420 for (; e != NULL; e = e->next) {
421 SCLogDebug("e %p e->name_idx %" PRIu32 ", e->data_ptr %p, e->data_len "
422 "%" PRIu32, e, e->name_idx,
423 e->data_ptr, e->data_len);
424
425 /* no parser defined for this field. */
426 if (e->name_idx != SSH_FIELD_CLIENT_VER_STATE_LINE) {
427 continue;
428 }
429
430 line_ptr = e->data_ptr;
431 line_len = e->data_len;
432 }
433
434 /* Update for the next round */
435 input_len -= offset;
436 input += offset;
437
438 if (line_ptr == NULL)
439 continue;
440 } else {
441 const uint8_t delim[] = { 0x0a, };
442 int r = AlpParseFieldByDelimiter(output, pstate,
443 SSH_FIELD_CLIENT_VER_STATE_LINE, delim, sizeof(delim),
444 input, input_len, &offset);
445
446 if (r == 0)
447 SCReturnInt(0);
448
449 /* Temporal pointer / len for the current line */
450 line_ptr = input;
451 line_len = offset;
452
453 /* Update for the next round */
454 input_len -= offset;
455 input += offset;
456 }
457
458 //PrintRawDataFp(stdout, line_ptr, line_len);
459
460 if (line_len < 5) {
461 SCLogDebug("This is not the version line we are searching for (probably a banner or informational messages)");
462 continue;
463 }
464
465 /* is it the version line? */
466 if (memcmp("SSH-", line_ptr, 4) == 0) {
467 if (line_len > 255) {
468 SCLogDebug("Invalid version string, it should be less than 255 characters including <CR><NL>");
469 SCReturnInt(-1);
470 }
471
472 /* ok, we have found the version line/string, skip it and parse proto version */
473 line_ptr += 4;
474 line_len -= 4;
475 } else {
476 SCLogDebug("This is not the version line we are searching for (probably a banner or informational messages)");
477 continue;
478 }
479
480 uint8_t *proto_end = BasicSearch(line_ptr, line_len, (uint8_t*)"-", 1);
481 if (proto_end == NULL) {
482 /* Strings starting with SSH- are not allowed
483 * if they are not the real version string */
484 SCLogDebug("Invalid Version String for SSH (invalid usage of SSH- prefix)");
485 SCReturnInt(-1);
486 }
487
488 uint64_t proto_ver_len = (uint64_t)(proto_end - line_ptr);
489 state->client_proto_version = SCMalloc(proto_ver_len + 1);
490 if (state->client_proto_version == NULL) {
491 SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
492 SCReturnInt(-1);
493 }
494 memcpy(state->client_proto_version, line_ptr, proto_ver_len);
495 state->client_proto_version[proto_ver_len] = '\0';
496
497 /* Now lets parse the software & version */
498 line_ptr += proto_ver_len + 1;
499 line_len -= proto_ver_len + 1;
500 if (line_len < 1) {
501 SCLogDebug("No software version specified (weird)");
502 state->flags |= SSH_FLAG_CLIENT_VERSION_PARSED;
503 /* Return the remaining length */
504 SCReturnInt(input_len);
505 }
506
507 uint8_t *sw_end = BasicSearch(line_ptr, line_len, (uint8_t*)" ", 1);
508 if (sw_end == NULL) {
509 sw_end = BasicSearch(line_ptr, line_len, (uint8_t*)"\r", 1);
510 if (sw_end == NULL) {
511 sw_end = line_ptr + line_len;
512 }
513 }
514
515 uint64_t sw_ver_len = (uint64_t)(sw_end - line_ptr);
516 state->client_software_version = SCMalloc(sw_ver_len + 1);
517 if (state->client_software_version == NULL) {
518 SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
519 SCReturnInt(-1);
520 }
521 memcpy(state->client_software_version, line_ptr, sw_ver_len);
522 state->client_software_version[sw_ver_len] = '\0';
523 if (state->client_software_version[sw_ver_len - 1] == 0x0d)
524 state->client_software_version[sw_ver_len - 1] = '\0';
525
526 state->flags |= SSH_FLAG_CLIENT_VERSION_PARSED;
527 /* Return the remaining length */
528 SCReturnInt(input_len);
529 }
530
531 SCReturnInt(0);
532 }
533
534 /**
535 * \brief Function to parse the SSH field in packet received from the client
536 *
537 * \param ssh_state Pointer the state in which the value to be stored
538 * \param pstate Application layer tarser state for this session
539 * \param input Pointer the received input data
540 * \param input_len Length in bytes of the received data
541 * \param output Pointer to the list of parsed output elements
542 */
543 static int SSHParseClientRecord(Flow *f, void *ssh_state, AppLayerParserState *pstate,
544 uint8_t *input, uint32_t input_len,
545 AppLayerParserResult *output)
546 {
547 SshState *state = (SshState *)ssh_state;
548 if (state->flags & SSH_FLAG_PARSER_DONE) {
549 SCReturnInt(0);
550 }
551
552 SCEnter();
553 int ret = 0;
554
555 SCLogDebug("ssh_state %p, pstate %p, input %p,input_len %" PRIu32 "",
556 ssh_state, pstate, input, input_len);
557 //PrintRawDataFp(stdout, input,input_len);
558
559 if (pstate == NULL)
560 SCReturnInt(-1);
561
562 if ( !(state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) {
563 ret = SSHParseClientVersion(f, ssh_state, pstate, input, input_len, output);
564 if (ret < 0) {
565 if (ret <= -1) {
566 SCLogDebug("Invalid version string");
567 SCReturnInt(-1);
568 }
569 SCLogDebug("Version string not parsed yet");
570 pstate->parse_field = 0;
571 SCReturnInt(0);
572 } else if (state->flags & SSH_FLAG_CLIENT_VERSION_PARSED) {
573 SCLogDebug("Version string parsed");
574 input += input_len - ret;
575 input_len -= (input_len - ret);
576 pstate->parse_field = 1;
577 ret = 1;
578 } else {
579 SCLogDebug("Version string not parsed yet");
580 pstate->parse_field = 0;
581 SCReturnInt(0);
582 }
583 } else {
584 SCLogDebug("Version string already parsed");
585 }
586
587 uint16_t max_fields = 4;
588 int16_t u = 0;
589 uint32_t offset = 0;
590
591 //printf("INPUT: \n");
592 //PrintRawDataFp(stdout, input,input_len);
593
594 if (pstate == NULL)
595 SCReturnInt(-1);
596
597 for (u = pstate->parse_field; u < max_fields; u++) {
598 SCLogDebug("u %" PRIu32 "", u);
599
600 switch(u % 4) {
601 case 0:
602 {
603 continue;
604 }
605 case 1: /* TLS CONTENT TYPE */
606 {
607 uint8_t *data = input + offset;
608 uint32_t data_len = input_len - offset;
609
610 int r = AlpParseFieldBySize(output, pstate,
611 SSH_FIELD_CLIENT_PKT_LENGTH,
612 /* single byte field */4, data,
613 data_len, &offset);
614 SCLogDebug("r = %" PRId32 "", r);
615
616 if (r == 0) {
617 pstate->parse_field = 1;
618 SCReturnInt(0);
619 } else if (r == -1) {
620 SCLogError(SC_ERR_ALPARSER, "AlpParseFieldBySize failed, "
621 "r %d", r);
622 SCReturnInt(-1);
623 }
624
625 uint32_t pkt_len = 0;
626 int ret = ByteExtractUint32(&pkt_len, BYTE_BIG_ENDIAN,
627 output->tail->data_len, output->tail->data_ptr);
628 if (ret != 4) {
629 SCReturnInt(-1);
630 }
631 state->cli_hdr.pkt_len = pkt_len;
632 SCLogDebug("pkt len: %"PRIu32"\n", pkt_len);
633
634 break;
635 }
636 case 2: /* TLS VERSION */
637 {
638 uint8_t *data = input + offset;
639 uint32_t data_len = input_len - offset;
640
641 int r = AlpParseFieldBySize(output, pstate,
642 SSH_FIELD_CLIENT_PADDING_LENGTH,
643 /* 2 byte field */1, data, data_len,
644 &offset);
645 if (r == 0) {
646 pstate->parse_field = 2;
647 SCReturnInt(0);
648 } else if (r == -1) {
649 SCLogError(SC_ERR_ALPARSER, "AlpParseFieldBySize failed, "
650 "r %d", r);
651 SCReturnInt(-1);
652 }
653 uint8_t padding_len = 0;
654 if (output->tail->data_len == 1) {
655 padding_len = (uint8_t) *output->tail->data_ptr;
656 SCLogDebug("padding len: %"PRIu8, padding_len);
657 }
658 state->cli_hdr.padding_len = padding_len;
659
660 break;
661 }
662 case 3: /* SSH_PAYLOAD */
663 {
664 uint8_t *data = input + offset;
665 uint32_t data_len = input_len - offset;
666
667 /* we add a -1 to the pkt len since the padding length is already parsed */
668 int r = AlpParseFieldBySize(output, pstate, SSH_FIELD_CLIENT_PAYLOAD,
669 /* 1 byte field */ state->cli_hdr.pkt_len - 1, data, data_len,
670 &offset);
671 SCLogDebug("AlpParseFieldBySize returned r %d, offset %"PRIu32,
672 r, offset);
673 if (r == 0) {
674 pstate->parse_field = 3;
675 SCReturnInt(0);
676 } else if (r == -1) {
677 SCLogError(SC_ERR_ALPARSER, "AlpParseFieldBySize failed, "
678 "r %d", r);
679 SCReturnInt(-1);
680 }
681
682 uint8_t msg_code = 0;
683 if (output->tail->data_len >= 1) {
684 msg_code = (uint8_t) *output->tail->data_ptr;
685 SCLogDebug("msg code: %"PRIu8, msg_code);
686 }
687
688 state->cli_hdr.msg_code = msg_code;
689 if (state->cli_hdr.msg_code == SSH_MSG_NEWKEYS) {
690 /* We are not going to inspect any packet more
691 * as the data is now encrypted */
692 SCLogDebug("SSH parser done (the rest of the communication is encrypted)");
693 state->flags |= SSH_FLAG_PARSER_DONE;
694 pstate->flags |= APP_LAYER_PARSER_DONE;
695 pstate->flags |= APP_LAYER_PARSER_NO_INSPECTION;
696 pstate->flags |= APP_LAYER_PARSER_NO_REASSEMBLY;
697 pstate->parse_field = 1;
698 SCReturnInt(1);
699 }
700
701 pstate->parse_field = 1;
702 ret = 1;
703
704 /* If we have remaining data, continue processing */
705 if (input_len - offset > 0) {
706 u = 0;
707 }
708
709 break;
710 }
711 }
712
713 }
714
715 SCReturnInt(ret);
716 }
717
718 /** \brief Function to allocates the SSH state memory
719 */
720 static void *SSHStateAlloc(void)
721 {
722 void *s = SCMalloc(sizeof(SshState));
723 if (s == NULL)
724 return NULL;
725
726 memset(s, 0, sizeof(SshState));
727 return s;
728 }
729
730 /** \brief Function to free the SSH state memory
731 */
732 static void SSHStateFree(void *state)
733 {
734 SshState *s = (SshState *)state;
735 if (s->client_proto_version != NULL)
736 SCFree(s->client_proto_version);
737 if (s->client_software_version != NULL)
738 SCFree(s->client_software_version);
739 if (s->server_proto_version != NULL)
740 SCFree(s->server_proto_version);
741 if (s->server_software_version != NULL)
742 SCFree(s->server_software_version);
743
744 SCFree(s);
745 }
746
747 /** \brief Function to register the SSH protocol parsers and other functions
748 */
749 void RegisterSSHParsers(void)
750 {
751 AppLayerRegisterProto("ssh", ALPROTO_SSH, STREAM_TOCLIENT,
752 SSHParseServerRecord);
753 AppLayerRegisterProto("ssh", ALPROTO_SSH, STREAM_TOSERVER,
754 SSHParseClientRecord);
755
756 AppLayerRegisterStateFuncs(ALPROTO_SSH, SSHStateAlloc, SSHStateFree);
757
758 }
759
760 /* UNITTESTS */
761 #ifdef UNITTESTS
762
763 /** \test Send a version string in one chunk (client version str). */
764 static int SSHParserTest01(void) {
765 int result = 0;
766 Flow f;
767 uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n";
768 uint32_t sshlen = sizeof(sshbuf) - 1;
769 TcpSession ssn;
770
771 memset(&f, 0, sizeof(f));
772 memset(&ssn, 0, sizeof(ssn));
773 f.protoctx = (void *)&ssn;
774
775 StreamTcpInitConfig(TRUE);
776 FlowL7DataPtrInit(&f);
777
778 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen);
779 if (r != 0) {
780 printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
781 result = 0;
782 goto end;
783 }
784
785 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
786 if (ssh_state == NULL) {
787 printf("no ssh state: ");
788 result = 0;
789 goto end;
790 }
791
792 if ( !(ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) {
793 printf("Client version string not parsed: ");
794 result = 0;
795 goto end;
796 }
797
798 if (ssh_state->client_software_version == NULL) {
799 printf("Client version string not parsed: ");
800 result = 0;
801 goto end;
802 }
803
804 if (ssh_state->client_proto_version == NULL) {
805 printf("Client version string not parsed: ");
806 result = 0;
807 goto end;
808 }
809
810 if (strncmp((char*)ssh_state->client_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
811 printf("Client version string not parsed correctly: ");
812 result = 0;
813 goto end;
814 }
815
816 if (strncmp((char*)ssh_state->client_proto_version, "2.0", strlen("2.0")) != 0) {
817 printf("Client version string not parsed correctly: ");
818 result = 0;
819 goto end;
820 }
821
822 result = 1;
823
824 end:
825 FlowL7DataPtrFree(&f);
826 StreamTcpFreeConfig(TRUE);
827 return result;
828 }
829
830 /** \test Send a version string in one chunk but multiple lines and comments.
831 * (client version str)
832 */
833 static int SSHParserTest02(void) {
834 int result = 0;
835 Flow f;
836 uint8_t sshbuf[] = "lalala\n lal al al\nSSH-2.0-MySSHClient-0.5.1 some comments...\n";
837 uint32_t sshlen = sizeof(sshbuf) - 1;
838 TcpSession ssn;
839
840 memset(&f, 0, sizeof(f));
841 memset(&ssn, 0, sizeof(ssn));
842 f.protoctx = (void *)&ssn;
843
844 StreamTcpInitConfig(TRUE);
845 FlowL7DataPtrInit(&f);
846
847 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen);
848 if (r != 0) {
849 printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
850 result = 0;
851 goto end;
852 }
853
854 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
855 if (ssh_state == NULL) {
856 printf("no ssh state: ");
857 result = 0;
858 goto end;
859 }
860
861 if ( !(ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) {
862 printf("Client version string not parsed: ");
863 result = 0;
864 goto end;
865 }
866
867 if (ssh_state->client_software_version == NULL) {
868 printf("Client version string not parsed: ");
869 result = 0;
870 goto end;
871 }
872
873 if (ssh_state->client_proto_version == NULL) {
874 printf("Client version string not parsed: ");
875 result = 0;
876 goto end;
877 }
878
879 if (strncmp((char*)ssh_state->client_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
880 printf("Client version string not parsed correctly: ");
881 result = 0;
882 goto end;
883 }
884
885 if (strncmp((char*)ssh_state->client_proto_version, "2.0", strlen("2.0")) != 0) {
886 printf("Client version string not parsed correctly: ");
887 result = 0;
888 goto end;
889 }
890
891 result = 1;
892
893 end:
894 FlowL7DataPtrFree(&f);
895 StreamTcpFreeConfig(TRUE);
896 return result;
897 }
898
899 /** \test Send a invalid version string in one chunk but multiple lines and comments.
900 * (client version str)
901 */
902 static int SSHParserTest03(void) {
903 int result = 0;
904 Flow f;
905 uint8_t sshbuf[] = "lalala\n lal al al\nSSH-2.0 some comments...\n";
906 uint32_t sshlen = sizeof(sshbuf) - 1;
907 TcpSession ssn;
908
909 memset(&f, 0, sizeof(f));
910 memset(&ssn, 0, sizeof(ssn));
911 f.protoctx = (void *)&ssn;
912
913 StreamTcpInitConfig(TRUE);
914 FlowL7DataPtrInit(&f);
915
916 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen);
917 if (r == 0) {
918 printf("toclient chunk 1 returned %" PRId32 ", expected != 0: ", r);
919 result = 0;
920 goto end;
921 }
922 /* Ok, it returned an error. Let's make sure we didn't parse the string at all */
923
924 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
925 if (ssh_state == NULL) {
926 printf("no ssh state: ");
927 result = 0;
928 goto end;
929 }
930
931 if (ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED) {
932 printf("Client version string parsed? It's not a valid string: ");
933 result = 0;
934 goto end;
935 }
936
937 if (ssh_state->client_proto_version != NULL) {
938 result = 0;
939 goto end;
940 }
941
942 if (ssh_state->client_software_version != NULL) {
943 result = 0;
944 goto end;
945 }
946
947 result = 1;
948
949 end:
950 FlowL7DataPtrFree(&f);
951 StreamTcpFreeConfig(TRUE);
952 return result;
953 }
954
955 /** \test Send a version string in one chunk (server version str). */
956 static int SSHParserTest04(void) {
957 int result = 0;
958 Flow f;
959 uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n";
960 uint32_t sshlen = sizeof(sshbuf) - 1;
961 TcpSession ssn;
962
963 memset(&f, 0, sizeof(f));
964 memset(&ssn, 0, sizeof(ssn));
965 f.protoctx = (void *)&ssn;
966
967 StreamTcpInitConfig(TRUE);
968 FlowL7DataPtrInit(&f);
969
970 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen);
971 if (r != 0) {
972 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
973 result = 0;
974 goto end;
975 }
976
977 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
978 if (ssh_state == NULL) {
979 printf("no ssh state: ");
980 result = 0;
981 goto end;
982 }
983
984 if ( !(ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) {
985 printf("Client version string not parsed: ");
986 result = 0;
987 goto end;
988 }
989
990 if (ssh_state->server_software_version == NULL) {
991 printf("Client version string not parsed: ");
992 result = 0;
993 goto end;
994 }
995
996 if (ssh_state->server_proto_version == NULL) {
997 printf("Client version string not parsed: ");
998 result = 0;
999 goto end;
1000 }
1001
1002 if (strncmp((char*)ssh_state->server_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1003 printf("Client version string not parsed correctly: ");
1004 result = 0;
1005 goto end;
1006 }
1007
1008 if (strncmp((char*)ssh_state->server_proto_version, "2.0", strlen("2.0")) != 0) {
1009 printf("Client version string not parsed correctly: ");
1010 result = 0;
1011 goto end;
1012 }
1013
1014 result = 1;
1015
1016 end:
1017 FlowL7DataPtrFree(&f);
1018 StreamTcpFreeConfig(TRUE);
1019 return result;
1020 }
1021
1022 /** \test Send a version string in one chunk but multiple lines and comments.
1023 * (server version str)
1024 */
1025 static int SSHParserTest05(void) {
1026 int result = 0;
1027 Flow f;
1028 uint8_t sshbuf[] = "lalala\n lal al al\nSSH-2.0-MySSHClient-0.5.1 some comments...\n";
1029 uint32_t sshlen = sizeof(sshbuf) - 1;
1030 TcpSession ssn;
1031
1032 memset(&f, 0, sizeof(f));
1033 memset(&ssn, 0, sizeof(ssn));
1034 f.protoctx = (void *)&ssn;
1035
1036 StreamTcpInitConfig(TRUE);
1037 FlowL7DataPtrInit(&f);
1038
1039 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen);
1040 if (r != 0) {
1041 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1042 result = 0;
1043 goto end;
1044 }
1045
1046 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
1047 if (ssh_state == NULL) {
1048 printf("no ssh state: ");
1049 result = 0;
1050 goto end;
1051 }
1052
1053 if ( !(ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) {
1054 printf("Client version string not parsed: ");
1055 result = 0;
1056 goto end;
1057 }
1058
1059 if (ssh_state->server_software_version == NULL) {
1060 printf("Client version string not parsed: ");
1061 result = 0;
1062 goto end;
1063 }
1064
1065 if (ssh_state->server_proto_version == NULL) {
1066 printf("Client version string not parsed: ");
1067 result = 0;
1068 goto end;
1069 }
1070
1071 if (strncmp((char*)ssh_state->server_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1072 printf("Client version string not parsed correctly: ");
1073 result = 0;
1074 goto end;
1075 }
1076
1077 if (strncmp((char*)ssh_state->server_proto_version, "2.0", strlen("2.0")) != 0) {
1078 printf("Client version string not parsed correctly: ");
1079 result = 0;
1080 goto end;
1081 }
1082
1083 result = 1;
1084
1085 end:
1086 FlowL7DataPtrFree(&f);
1087 StreamTcpFreeConfig(TRUE);
1088 return result;
1089 }
1090
1091 /** \test Send a invalid version string in one chunk but multiple lines and comments.
1092 * (server version str)
1093 */
1094 static int SSHParserTest06(void) {
1095 int result = 0;
1096 Flow f;
1097 uint8_t sshbuf[] = "lalala\n lal al al\nSSH-2.0 some comments...\n";
1098 uint32_t sshlen = sizeof(sshbuf) - 1;
1099 TcpSession ssn;
1100
1101 memset(&f, 0, sizeof(f));
1102 memset(&ssn, 0, sizeof(ssn));
1103 f.protoctx = (void *)&ssn;
1104
1105 StreamTcpInitConfig(TRUE);
1106 FlowL7DataPtrInit(&f);
1107
1108 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen);
1109 if (r == 0) {
1110 printf("toserver chunk 1 returned %" PRId32 ", expected != 0: ", r);
1111 result = 0;
1112 goto end;
1113 }
1114 /* Ok, it returned an error. Let's make sure we didn't parse the string at all */
1115
1116 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
1117 if (ssh_state == NULL) {
1118 printf("no ssh state: ");
1119 result = 0;
1120 goto end;
1121 }
1122
1123 if (ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED) {
1124 printf("Client version string parsed? It's not a valid string: ");
1125 result = 0;
1126 goto end;
1127 }
1128
1129 if (ssh_state->server_proto_version != NULL) {
1130 result = 0;
1131 goto end;
1132 }
1133
1134 if (ssh_state->server_software_version != NULL) {
1135 result = 0;
1136 goto end;
1137 }
1138
1139 result = 1;
1140
1141 end:
1142 FlowL7DataPtrFree(&f);
1143 StreamTcpFreeConfig(TRUE);
1144 return result;
1145 }
1146
1147 static int SSHParserTest07(void) {
1148 int result = 0;
1149 Flow f;
1150 uint8_t sshbuf1[] = "SSH-2.";
1151 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1152 uint8_t sshbuf2[] = { "0-MySSHClient-0.5.1\r\n"};
1153 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
1154 TcpSession ssn;
1155
1156 memset(&f, 0, sizeof(f));
1157 memset(&ssn, 0, sizeof(ssn));
1158 f.protoctx = (void *)&ssn;
1159
1160 StreamTcpInitConfig(TRUE);
1161 FlowL7DataPtrInit(&f);
1162
1163 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
1164 if (r != 0) {
1165 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1166 goto end;
1167 }
1168
1169 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
1170 if (r != 0) {
1171 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1172 goto end;
1173 }
1174
1175 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
1176 if (ssh_state == NULL) {
1177 printf("no ssh state: ");
1178 goto end;
1179 }
1180
1181 if ( !(ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) {
1182 printf("Client version string not parsed: ");
1183 goto end;
1184 }
1185
1186 if (ssh_state->client_software_version == NULL) {
1187 printf("Client version string not parsed: ");
1188 goto end;
1189 }
1190
1191 if (ssh_state->client_proto_version == NULL) {
1192 printf("Client version string not parsed: ");
1193 goto end;
1194 }
1195
1196 if (strncmp((char*)ssh_state->client_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1197 printf("Client version string not parsed correctly: ");
1198 goto end;
1199 }
1200
1201 if (strncmp((char*)ssh_state->client_proto_version, "2.0", strlen("2.0")) != 0) {
1202 printf("Client version string not parsed correctly: ");
1203 goto end;
1204 }
1205
1206 result = 1;
1207
1208 end:
1209 FlowL7DataPtrFree(&f);
1210 StreamTcpFreeConfig(TRUE);
1211 return result;
1212 }
1213
1214 /** \test Send a version banner in three chunks. */
1215 static int SSHParserTest08(void) {
1216 int result = 0;
1217 Flow f;
1218 uint8_t sshbuf1[] = "Welcome to this ssh server\nSSH-";
1219 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1220 uint8_t sshbuf2[] = "2.";
1221 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
1222 uint8_t sshbuf3[] = { "0-MySSHClient-0.5.1\r\n"};
1223 uint32_t sshlen3 = sizeof(sshbuf3) - 1;
1224 TcpSession ssn;
1225
1226 memset(&f, 0, sizeof(f));
1227 memset(&ssn, 0, sizeof(ssn));
1228 f.protoctx = (void *)&ssn;
1229
1230 StreamTcpInitConfig(TRUE);
1231 FlowL7DataPtrInit(&f);
1232
1233 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
1234 if (r != 0) {
1235 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1236 goto end;
1237 }
1238
1239 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
1240 if (r != 0) {
1241 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1242 goto end;
1243 }
1244
1245 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
1246 if (r != 0) {
1247 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1248 goto end;
1249 }
1250
1251 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
1252 if (ssh_state == NULL) {
1253 printf("no ssh state: ");
1254 goto end;
1255 }
1256
1257 if ( !(ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) {
1258 printf("Client version string not parsed: ");
1259 goto end;
1260 }
1261
1262 if (ssh_state->client_software_version == NULL) {
1263 printf("Client version string not parsed: ");
1264 goto end;
1265 }
1266
1267 if (ssh_state->client_proto_version == NULL) {
1268 printf("Client version string not parsed: ");
1269 goto end;
1270 }
1271
1272 if (strncmp((char*)ssh_state->client_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1273 printf("Client version string not parsed correctly: ");
1274 goto end;
1275 }
1276
1277 if (strncmp((char*)ssh_state->client_proto_version, "2.0", strlen("2.0")) != 0) {
1278 printf("Client version string not parsed correctly: ");
1279 goto end;
1280 }
1281
1282 result = 1;
1283 end:
1284 FlowL7DataPtrFree(&f);
1285 StreamTcpFreeConfig(TRUE);
1286 return result;
1287 }
1288
1289 static int SSHParserTest09(void) {
1290 int result = 0;
1291 Flow f;
1292 uint8_t sshbuf1[] = "SSH-2.";
1293 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1294 uint8_t sshbuf2[] = { "0-MySSHClient-0.5.1\r\n"};
1295 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
1296 TcpSession ssn;
1297
1298 memset(&f, 0, sizeof(f));
1299 memset(&ssn, 0, sizeof(ssn));
1300 f.protoctx = (void *)&ssn;
1301
1302 StreamTcpInitConfig(TRUE);
1303 FlowL7DataPtrInit(&f);
1304
1305 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1);
1306 if (r != 0) {
1307 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1308 goto end;
1309 }
1310
1311 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2);
1312 if (r != 0) {
1313 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1314 goto end;
1315 }
1316
1317 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
1318 if (ssh_state == NULL) {
1319 printf("no ssh state: ");
1320 goto end;
1321 }
1322
1323 if ( !(ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) {
1324 printf("Client version string not parsed: ");
1325 goto end;
1326 }
1327
1328 if (ssh_state->server_software_version == NULL) {
1329 printf("Client version string not parsed: ");
1330 goto end;
1331 }
1332
1333 if (ssh_state->server_proto_version == NULL) {
1334 printf("Client version string not parsed: ");
1335 goto end;
1336 }
1337
1338 if (strncmp((char*)ssh_state->server_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1339 printf("Client version string not parsed correctly: ");
1340 goto end;
1341 }
1342
1343 if (strncmp((char*)ssh_state->server_proto_version, "2.0", strlen("2.0")) != 0) {
1344 printf("Client version string not parsed correctly: ");
1345 goto end;
1346 }
1347
1348 result = 1;
1349
1350 end:
1351 FlowL7DataPtrFree(&f);
1352 StreamTcpFreeConfig(TRUE);
1353 return result;
1354 }
1355
1356 /** \test Send a version banner in three chunks. */
1357 static int SSHParserTest10(void) {
1358 int result = 0;
1359 Flow f;
1360 uint8_t sshbuf1[] = "Welcome to this ssh server\nSSH-";
1361 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1362 uint8_t sshbuf2[] = "2.";
1363 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
1364 uint8_t sshbuf3[] = { "0-MySSHClient-0.5.1\r\n"};
1365 uint32_t sshlen3 = sizeof(sshbuf3) - 1;
1366 TcpSession ssn;
1367
1368 memset(&f, 0, sizeof(f));
1369 memset(&ssn, 0, sizeof(ssn));
1370 f.protoctx = (void *)&ssn;
1371
1372 StreamTcpInitConfig(TRUE);
1373 FlowL7DataPtrInit(&f);
1374
1375 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1);
1376 if (r != 0) {
1377 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1378 goto end;
1379 }
1380
1381 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2);
1382 if (r != 0) {
1383 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1384 goto end;
1385 }
1386
1387 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3);
1388 if (r != 0) {
1389 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1390 goto end;
1391 }
1392
1393 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
1394 if (ssh_state == NULL) {
1395 printf("no ssh state: ");
1396 goto end;
1397 }
1398
1399 if ( !(ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) {
1400 printf("Client version string not parsed: ");
1401 goto end;
1402 }
1403
1404 if (ssh_state->server_software_version == NULL) {
1405 printf("Client version string not parsed: ");
1406 goto end;
1407 }
1408
1409 if (ssh_state->server_proto_version == NULL) {
1410 printf("Client version string not parsed: ");
1411 goto end;
1412 }
1413
1414 if (strncmp((char*)ssh_state->server_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1415 printf("Client version string not parsed correctly: ");
1416 goto end;
1417 }
1418
1419 if (strncmp((char*)ssh_state->server_proto_version, "2.0", strlen("2.0")) != 0) {
1420 printf("Client version string not parsed correctly: ");
1421 goto end;
1422 }
1423
1424 result = 1;
1425 end:
1426 FlowL7DataPtrFree(&f);
1427 StreamTcpFreeConfig(TRUE);
1428 return result;
1429 }
1430
1431 /** \test Send a banner and record in three chunks. */
1432 static int SSHParserTest11(void) {
1433 int result = 0;
1434 Flow f;
1435 uint8_t sshbuf1[] = "Welcome to this ssh server\nSSH-";
1436 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1437 uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
1438 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
1439 uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00};
1440 uint32_t sshlen3 = sizeof(sshbuf3);
1441 TcpSession ssn;
1442
1443 memset(&f, 0, sizeof(f));
1444 memset(&ssn, 0, sizeof(ssn));
1445 f.protoctx = (void *)&ssn;
1446
1447 StreamTcpInitConfig(TRUE);
1448 FlowL7DataPtrInit(&f);
1449
1450 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
1451 if (r != 0) {
1452 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1453 goto end;
1454 }
1455
1456 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
1457 if (r != 0) {
1458 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1459 goto end;
1460 }
1461
1462 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
1463 if (r != 0) {
1464 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1465 goto end;
1466 }
1467
1468 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
1469 if (ssh_state == NULL) {
1470 printf("no ssh state: ");
1471 goto end;
1472 }
1473
1474 if ( !(ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) {
1475 printf("Client version string not parsed: ");
1476 goto end;
1477 }
1478
1479 if (ssh_state->client_software_version == NULL) {
1480 printf("Client version string not parsed: ");
1481 goto end;
1482 }
1483
1484 if (ssh_state->client_proto_version == NULL) {
1485 printf("Client version string not parsed: ");
1486 goto end;
1487 }
1488
1489 if (strncmp((char*)ssh_state->client_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1490 printf("Client version string not parsed correctly: ");
1491 goto end;
1492 }
1493
1494 if (strncmp((char*)ssh_state->client_proto_version, "2.0", strlen("2.0")) != 0) {
1495 printf("Client version string not parsed correctly: ");
1496 goto end;
1497 }
1498
1499 if ( !(ssh_state->flags & SSH_FLAG_PARSER_DONE)) {
1500 printf("Didn't detect the msg code of new keys (ciphered data starts): ");
1501 goto end;
1502 }
1503
1504 result = 1;
1505 end:
1506 FlowL7DataPtrFree(&f);
1507 StreamTcpFreeConfig(TRUE);
1508 return result;
1509 }
1510
1511 /** \test Send a banner and 2 records record in four chunks. */
1512 static int SSHParserTest12(void) {
1513 int result = 0;
1514 Flow f;
1515 uint8_t sshbuf1[] = "Welcome to this ssh server\nSSH-";
1516 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1517 uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
1518 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
1519 uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 17, 0x00};
1520 uint32_t sshlen3 = sizeof(sshbuf3);
1521 uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00};
1522 uint32_t sshlen4 = sizeof(sshbuf4);
1523 TcpSession ssn;
1524
1525 memset(&f, 0, sizeof(f));
1526 memset(&ssn, 0, sizeof(ssn));
1527 f.protoctx = (void *)&ssn;
1528
1529 StreamTcpInitConfig(TRUE);
1530 FlowL7DataPtrInit(&f);
1531
1532 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
1533 if (r != 0) {
1534 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1535 goto end;
1536 }
1537
1538 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
1539 if (r != 0) {
1540 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1541 goto end;
1542 }
1543
1544 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
1545 if (r != 0) {
1546 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1547 goto end;
1548 }
1549
1550 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4);
1551 if (r != 0) {
1552 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
1553 goto end;
1554 }
1555
1556 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
1557 if (ssh_state == NULL) {
1558 printf("no ssh state: ");
1559 goto end;
1560 }
1561
1562 if ( !(ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED)) {
1563 printf("Client version string not parsed: ");
1564 goto end;
1565 }
1566
1567 if (ssh_state->client_software_version == NULL) {
1568 printf("Client version string not parsed: ");
1569 goto end;
1570 }
1571
1572 if (ssh_state->client_proto_version == NULL) {
1573 printf("Client version string not parsed: ");
1574 goto end;
1575 }
1576
1577 if (strncmp((char*)ssh_state->client_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1578 printf("Client version string not parsed correctly: ");
1579 goto end;
1580 }
1581
1582 if (strncmp((char*)ssh_state->client_proto_version, "2.0", strlen("2.0")) != 0) {
1583 printf("Client version string not parsed correctly: ");
1584 goto end;
1585 }
1586
1587 if ( !(ssh_state->flags & SSH_FLAG_PARSER_DONE)) {
1588 printf("Didn't detect the msg code of new keys (ciphered data starts): ");
1589 goto end;
1590 }
1591
1592 result = 1;
1593 end:
1594 FlowL7DataPtrFree(&f);
1595 StreamTcpFreeConfig(TRUE);
1596 return result;
1597 }
1598
1599 /** \test Send toserver a banner and record in three chunks. */
1600 static int SSHParserTest13(void) {
1601 int result = 0;
1602 Flow f;
1603 uint8_t sshbuf1[] = "Welcome to this ssh server\nSSH-";
1604 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1605 uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
1606 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
1607 uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00};
1608 uint32_t sshlen3 = sizeof(sshbuf3);
1609 TcpSession ssn;
1610
1611 memset(&f, 0, sizeof(f));
1612 memset(&ssn, 0, sizeof(ssn));
1613 f.protoctx = (void *)&ssn;
1614
1615 StreamTcpInitConfig(TRUE);
1616 FlowL7DataPtrInit(&f);
1617
1618 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1);
1619 if (r != 0) {
1620 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1621 goto end;
1622 }
1623
1624 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2);
1625 if (r != 0) {
1626 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1627 goto end;
1628 }
1629
1630 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3);
1631 if (r != 0) {
1632 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1633 goto end;
1634 }
1635
1636 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
1637 if (ssh_state == NULL) {
1638 printf("no ssh state: ");
1639 goto end;
1640 }
1641
1642 if ( !(ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) {
1643 printf("Client version string not parsed: ");
1644 goto end;
1645 }
1646
1647 if (ssh_state->server_software_version == NULL) {
1648 printf("Client version string not parsed: ");
1649 goto end;
1650 }
1651
1652 if (ssh_state->server_proto_version == NULL) {
1653 printf("Client version string not parsed: ");
1654 goto end;
1655 }
1656
1657 if (strncmp((char*)ssh_state->server_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1658 printf("Client version string not parsed correctly: ");
1659 goto end;
1660 }
1661
1662 if (strncmp((char*)ssh_state->server_proto_version, "2.0", strlen("2.0")) != 0) {
1663 printf("Client version string not parsed correctly: ");
1664 goto end;
1665 }
1666
1667 if ( !(ssh_state->flags & SSH_FLAG_PARSER_DONE)) {
1668 printf("Didn't detect the msg code of new keys (ciphered data starts): ");
1669 goto end;
1670 }
1671
1672 result = 1;
1673 end:
1674 FlowL7DataPtrFree(&f);
1675 StreamTcpFreeConfig(TRUE);
1676 return result;
1677 }
1678
1679 /** \test Send toserver a banner and 2 records record in four chunks. */
1680 static int SSHParserTest14(void) {
1681 int result = 0;
1682 Flow f;
1683 uint8_t sshbuf1[] = "Welcome to this ssh server\nSSH-";
1684 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1685 uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
1686 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
1687 uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 17, 0x00};
1688 uint32_t sshlen3 = sizeof(sshbuf3);
1689 uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00};
1690 uint32_t sshlen4 = sizeof(sshbuf4);
1691 TcpSession ssn;
1692
1693 memset(&f, 0, sizeof(f));
1694 memset(&ssn, 0, sizeof(ssn));
1695 f.protoctx = (void *)&ssn;
1696
1697 StreamTcpInitConfig(TRUE);
1698 FlowL7DataPtrInit(&f);
1699
1700 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1);
1701 if (r != 0) {
1702 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1703 goto end;
1704 }
1705
1706 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2);
1707 if (r != 0) {
1708 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1709 goto end;
1710 }
1711
1712 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3);
1713 if (r != 0) {
1714 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1715 goto end;
1716 }
1717
1718 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4);
1719 if (r != 0) {
1720 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
1721 goto end;
1722 }
1723
1724 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
1725 if (ssh_state == NULL) {
1726 printf("no ssh state: ");
1727 goto end;
1728 }
1729
1730 if ( !(ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED)) {
1731 printf("Client version string not parsed: ");
1732 goto end;
1733 }
1734
1735 if (ssh_state->server_software_version == NULL) {
1736 printf("Client version string not parsed: ");
1737 goto end;
1738 }
1739
1740 if (ssh_state->server_proto_version == NULL) {
1741 printf("Client version string not parsed: ");
1742 goto end;
1743 }
1744
1745 if (strncmp((char*)ssh_state->server_software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1746 printf("Client version string not parsed correctly: ");
1747 goto end;
1748 }
1749
1750 if (strncmp((char*)ssh_state->server_proto_version, "2.0", strlen("2.0")) != 0) {
1751 printf("Client version string not parsed correctly: ");
1752 goto end;
1753 }
1754
1755 if ( !(ssh_state->flags & SSH_FLAG_PARSER_DONE)) {
1756 printf("Didn't detect the msg code of new keys (ciphered data starts): ");
1757 goto end;
1758 }
1759
1760 result = 1;
1761 end:
1762 FlowL7DataPtrFree(&f);
1763 StreamTcpFreeConfig(TRUE);
1764 return result;
1765 }
1766
1767 #endif /* UNITTESTS */
1768
1769 void SSHParserRegisterTests(void) {
1770 #ifdef UNITTESTS
1771 UtRegisterTest("SSHParserTest01 - ToServer", SSHParserTest01, 1);
1772 UtRegisterTest("SSHParserTest02 - ToServer", SSHParserTest02, 1);
1773 UtRegisterTest("SSHParserTest03 - ToServer", SSHParserTest03, 1);
1774 UtRegisterTest("SSHParserTest04 - ToClient", SSHParserTest04, 1);
1775 UtRegisterTest("SSHParserTest05 - ToClient", SSHParserTest05, 1);
1776 UtRegisterTest("SSHParserTest06 - ToClient", SSHParserTest06, 1);
1777 UtRegisterTest("SSHParserTest07 - ToServer 2 chunks", SSHParserTest07, 1);
1778 UtRegisterTest("SSHParserTest08 - ToServer 3 chunks", SSHParserTest08, 1);
1779 UtRegisterTest("SSHParserTest09 - ToClient 2 chunks", SSHParserTest09, 1);
1780 UtRegisterTest("SSHParserTest10 - ToClient 3 chunks", SSHParserTest10, 1);
1781 UtRegisterTest("SSHParserTest11 - ToClient 4 chunks", SSHParserTest11, 1);
1782 UtRegisterTest("SSHParserTest12 - ToClient 4 chunks", SSHParserTest12, 1);
1783 UtRegisterTest("SSHParserTest13 - ToClient 4 chunks", SSHParserTest13, 1);
1784 UtRegisterTest("SSHParserTest14 - ToClient 4 chunks", SSHParserTest14, 1);
1785 #endif /* UNITTESTS */
1786 }
0 /* Copyright (C) 2007-2010 Open Information Security Foundation
1 *
2 * You can copy, redistribute or modify this Program under the terms of
3 * the GNU General Public License version 2 as published by the Free
4 * Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * version 2 along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
14 * 02110-1301, USA.
15 */
16
17 /**
18 * \file
19 *
20 * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
21 */
22
23 #ifndef __APP_LAYER_SSH_H__
24 #define __APP_LAYER_SSH_H__
25
26 #define SSH_FLAG_SERVER_CHANGE_CIPHER_SPEC 0x01 /**< Flag to indicate that
27 server will now on sends
28 encrypted msgs. */
29 #define SSH_FLAG_CLIENT_CHANGE_CIPHER_SPEC 0x02 /**< Flag to indicate that
30 client will now on sends
31 encrypted msgs. */
32
33 #define SSH_FLAG_CLIENT_VERSION_PARSED 0x01
34 #define SSH_FLAG_SERVER_VERSION_PARSED 0x02
35
36 /* This flags indicate that the rest of the communication
37 * must be ciphered, so the parsing finish here */
38 #define SSH_FLAG_PARSER_DONE 0x04
39
40 /* MSG_CODE */
41 #define SSH_MSG_NEWKEYS 21
42
43 enum {
44 SSH_FIELD_NONE = 0,
45 SSH_FIELD_SERVER_VER_STATE_LINE,
46 SSH_FIELD_CLIENT_VER_STATE_LINE,
47 SSH_FIELD_SERVER_PKT_LENGTH,
48 SSH_FIELD_CLIENT_PKT_LENGTH,
49 SSH_FIELD_SERVER_PADDING_LENGTH,
50 SSH_FIELD_CLIENT_PADDING_LENGTH,
51 SSH_FIELD_SERVER_PAYLOAD,
52 SSH_FIELD_CLIENT_PAYLOAD,
53
54 /* must be last */
55 SSH_FIELD_MAX,
56 };
57
58 /** From SSH-TRANSP rfc
59
60 SSH Bunary packet structure:
61 uint32 packet_length
62 byte padding_length
63 byte[n1] payload; n1 = packet_length - padding_length - 1
64 byte[n2] random padding; n2 = padding_length
65 byte[m] mac (Message Authentication Code - MAC); m = mac_length
66
67 So we are going to do a header struct to store
68 the lenghts and msg_code (inside payload, if any)
69 */
70
71 typedef struct SSHHeader_ {
72 uint32_t pkt_len;
73 uint8_t padding_len;
74 uint8_t msg_code;
75 } SshHeader;
76
77 /** structure to store the SSH state values */
78 typedef struct SshState_ {
79 uint8_t client_msg_code; /**< Client content type storage field */
80 uint8_t *client_proto_version; /**< Client SSH version storage field */
81 uint8_t *client_software_version; /**< Client SSH version storage field */
82
83 uint8_t server_msg_code; /**< Server content type storage field */
84 uint8_t *server_proto_version; /**< Server SSH version storage field */
85 uint8_t *server_software_version; /**< Server SSH version storage field */
86
87 uint8_t flags; /**< Flags to indicate the current SSH
88 sessoin state */
89 SshHeader srv_hdr;
90 SshHeader cli_hdr;
91 } SshState;
92
93 void RegisterSSHParsers(void);
94 void SSHParserRegisterTests(void);
95
96 #endif /* __APP_LAYER_SSH_H__ */
97
3131 #include "flow.h"
3232
3333 #include "util-debug.h"
34
35 extern uint8_t engine_mode;
3436
3537 /** \brief Get the active app layer proto from the packet
3638 * \param p packet pointer
208208 char *msg;
209209 char *class_msg;
210210 Reference *references;
211 uint8_t flags;
211212 } PacketAlert;
213
214 /* After processing an alert by the thresholding module, if at
215 * last it gets triggered, we might want to stick the drop action to
216 * the flow on IPS mode */
217 #define PACKET_ALERT_FLAG_DROP_FLOW 0x01
212218
213219 #define PACKET_ALERT_MAX 256
214220
6363 return MpmPatternIdStoreGetMaxId(de_ctx->mpm_pattern_id_store);
6464 }
6565
66 /**
67 * \brief DetectContentParse
68 * \initonly
69 */
6670 DetectContentData *DetectContentParse (char *contentstr)
6771 {
6872 DetectContentData *cd = NULL;
7377 uint16_t slen = 0;
7478
7579 if ((temp = SCStrdup(contentstr)) == NULL) {
76 SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
77 goto error;
80 SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory. Exiting...");
81 exit(EXIT_FAILURE);
7882 }
7983
8084 if (strlen(temp) == 0) {
8387 }
8488
8589 cd = SCMalloc(sizeof(DetectContentData));
86 if (cd == NULL)
87 goto error;
90 if (cd == NULL) {
91 SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory. Exiting...");
92 exit(EXIT_FAILURE);
93 }
94
8895 memset(cd, 0, sizeof(DetectContentData));
8996
9097 /* skip the first spaces */
95102
96103 if (temp[pos] == '!') {
97104 SCFree(temp);
98 if ((temp = SCStrdup(contentstr + pos + 1)) == NULL)
99 goto error;
105 if ((temp = SCStrdup(contentstr + pos + 1)) == NULL) {
106 SCLogError(SC_ERR_MEM_ALLOC, "error allocating memory. exiting...");
107 exit(EXIT_FAILURE);
108 }
100109
101110 cd->flags |= DETECT_CONTENT_NEGATED;
102111 }
103112
104113 if (temp[pos] == '\"' && temp[strlen(temp)-1] == '\"') {
105 if ((str = SCStrdup(temp + pos + 1)) == NULL)
106 goto error;
114 if ((str = SCStrdup(temp + pos + 1)) == NULL) {
115 SCLogError(SC_ERR_MEM_ALLOC, "error allocating memory. exiting...");
116 exit(EXIT_FAILURE);
117 }
118
107119 str[strlen(temp) - pos - 2] = '\0';
108120 } else {
109 if ((str = SCStrdup(temp + pos)) == NULL)
110 goto error;
121 if ((str = SCStrdup(temp + pos)) == NULL) {
122 SCLogError(SC_ERR_MEM_ALLOC, "error allocating memory. exiting...");
123 exit(EXIT_FAILURE);
124 }
111125 }
112126
113127 SCFree(temp);
215229 }
216230
217231 cd->content = SCMalloc(len);
218 if (cd->content == NULL)
219 goto error;
232 if (cd->content == NULL) {
233 SCLogError(SC_ERR_MEM_ALLOC, "error allocating memory. exiting...");
234 exit(EXIT_FAILURE);
235 }
220236
221237 memcpy(cd->content, str, len);
222238 cd->content_len = len;
152152 &s->pmatch, &s->pmatch_tail,
153153 &s->dmatch, &s->dmatch_tail);
154154 pm = pm1;
155 } else if (pm2_ots->idx > dcem->idx) {
155 } else {
156156 /* within is against pm1, pm = pm1 */
157157 pm = pm1;
158158 }
109109 return match;
110110 }
111111
112 int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p)
112 int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p, uint8_t flags)
113113 {
114114 int i = 0;
115115
137137 p->alerts.alerts[p->alerts.cnt].class = s->class;
138138 p->alerts.alerts[p->alerts.cnt].class_msg = s->class_msg;
139139 p->alerts.alerts[p->alerts.cnt].references = s->references;
140 p->alerts.alerts[p->alerts.cnt].flags = flags;
140141 } else {
141142 /* We need to make room for this s->num
142143 (a bit ugly with mamcpy but we are planning changes here)*/
161162 p->alerts.alerts[i].class = s->class;
162163 p->alerts.alerts[i].class_msg = s->class_msg;
163164 p->alerts.alerts[i].references = s->references;
165 p->alerts.alerts[i].flags = flags;
164166 }
165167
166168 /* Update the count */
255257 * so we ignore the rest with less prio */
256258 p->alerts.cnt = i;
257259 break;
260 } else if ( ((p->alerts.alerts[i].flags & PACKET_ALERT_FLAG_DROP_FLOW) ||
261 (s->flags & SIG_FLAG_APPLAYER))
262 && p->flow != NULL)
263 {
264 SCMutexLock(&p->flow->m);
265 /* This will apply only on IPS mode (check StreamTcpPacket) */
266 p->flow->flags |= FLOW_ACTION_DROP;
267 SCMutexUnlock(&p->flow->m);
258268 }
259269 }
260270 /* Because we removed the alert from the array, we should
2727 #include "detect.h"
2828
2929 void PacketAlertFinalize(DetectEngineCtx *, DetectEngineThreadCtx *, Packet *);
30 int PacketAlertAppend(DetectEngineThreadCtx *, Signature *, Packet *);
30 int PacketAlertAppend(DetectEngineThreadCtx *, Signature *, Packet *, uint8_t);
3131 int PacketAlertAppendTag(Packet *, PacketAlert *);
3232 int PacketAlertCheck(Packet *, uint32_t);
3333 int PacketAlertRemove(Packet *, uint16_t);
982982 u * 8 + i, s->id, s->msg);
983983
984984 if ( !(s->flags & SIG_FLAG_NOALERT)) {
985 PacketAlertAppend(det_ctx, s, p);
985 if (s->action & ACTION_DROP)
986 PacketAlertAppend(det_ctx, s, p, PACKET_ALERT_FLAG_DROP_FLOW);
987 else
988 PacketAlertAppend(det_ctx, s, p, 0);
986989 }
987990 }
988991 }
15961596 * \param co content pattern data
15971597 *
15981598 * \retval id pattern id
1599 * \initonly
15991600 */
16001601 uint32_t DetectContentGetId(MpmPatternIdStore *ht, DetectContentData *co) {
16011602 SCEnter();
101101 goto end;
102102 }
103103
104 if (htp_state->body.nchunks == 0) {
105 SCLogDebug("No http chunks to inspect");
106 goto end;
107 } else {
108 HtpBodyChunk *cur = htp_state->body.first;
109 /* no chunks?!! get out of here */
110 if (cur == NULL) {
104 htp_tx_t *tx = NULL;
105 size_t idx = 0;
106
107 for (idx = 0;//hs->new_in_tx_index;
108 idx < list_size(htp_state->connp->conn->transactions); idx++)
109 {
110 tx = list_get(htp_state->connp->conn->transactions, idx);
111 if (tx == NULL)
112 continue;
113
114 SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(tx);
115 if (htud == NULL)
116 continue;
117
118 HtpBodyChunk *cur = htud->body.first;
119
120 if (htud->body.nchunks == 0) {
111121 SCLogDebug("No http chunks to inspect");
112122 goto end;
123 } else {
124 /* no chunks?!! get out of here */
125 if (cur == NULL) {
126 SCLogDebug("No http chunks to inspect");
127 goto end;
128 }
129
130 /* this applies only for the client request body like the keyword name says */
131 if (htud->body.operation != HTP_BODY_REQUEST) {
132 SCLogDebug("htp chunk not a request chunk");
133 goto end;
134 }
135
136 /* this is not how we do it now. We can rather hold the PM state from
137 * the previous chunk that was matched, and continue right from where
138 * we left off. We need to devise a scheme to do that, not just for
139 * this keyword, but other keywords need it as well */
140 uint8_t *chunks_buffer = NULL;
141 uint32_t total_chunks_len = 0;
142 /* club all the chunks into one whole buffer and call the SPM on the buffer */
143 while (cur != NULL) {
144 total_chunks_len += cur->len;
145 if ( (chunks_buffer = SCRealloc(chunks_buffer, total_chunks_len)) == NULL) {
146 return 0;
147 }
148 memcpy(chunks_buffer + total_chunks_len - cur->len, cur->data, cur->len);
149 cur = cur->next;
150 }
151 /* call the case insensitive version if nocase has been specified in the sig */
152 if (hcbd->flags & DETECT_AL_HTTP_CLIENT_BODY_NOCASE) {
153 result = (BoyerMooreNocase(hcbd->content, hcbd->content_len, chunks_buffer,
154 total_chunks_len, hcbd->bm_ctx->bmGs,
155 hcbd->bm_ctx->bmBc) != NULL);
156 /* call the case sensitive version if nocase has been specified in the sig */
157 } else {
158 result = (BoyerMoore(hcbd->content, hcbd->content_len, chunks_buffer,
159 total_chunks_len, hcbd->bm_ctx->bmGs,
160 hcbd->bm_ctx->bmBc) != NULL);
161 }
162 SCFree(chunks_buffer);
113163 }
114
115 /* this applies only for the client request body like the keyword name says */
116 if (htp_state->body.operation != HTP_BODY_REQUEST) {
117 SCLogDebug("htp chunk not a request chunk");
118 goto end;
119 }
120
121 /* this is not how we do it now. We can rather hold the PM state from
122 * the previous chunk that was matched, and continue right from where
123 * we left off. We need to devise a scheme to do that, not just for
124 * this keyword, but other keywords need it as well */
125 uint8_t *chunks_buffer = NULL;
126 uint32_t total_chunks_len = 0;
127 /* club all the chunks into one whole buffer and call the SPM on the buffer */
128 while (cur != NULL) {
129 total_chunks_len += cur->len;
130 if ( (chunks_buffer = SCRealloc(chunks_buffer, total_chunks_len)) == NULL) {
131 return 0;
132 }
133 memcpy(chunks_buffer + total_chunks_len - cur->len, cur->data, cur->len);
134 cur = cur->next;
135 }
136 /* call the case insensitive version if nocase has been specified in the sig */
137 if (hcbd->flags & DETECT_AL_HTTP_CLIENT_BODY_NOCASE) {
138 result = (BoyerMooreNocase(hcbd->content, hcbd->content_len, chunks_buffer,
139 total_chunks_len, hcbd->bm_ctx->bmGs,
140 hcbd->bm_ctx->bmBc) != NULL);
141 /* call the case sensitive version if nocase has been specified in the sig */
142 } else {
143 result = (BoyerMoore(hcbd->content, hcbd->content_len, chunks_buffer,
144 total_chunks_len, hcbd->bm_ctx->bmGs,
145 hcbd->bm_ctx->bmBc) != NULL);
146 }
147 SCFree(chunks_buffer);
148164 }
149165
150166 SCMutexUnlock(&f->m);
13191335 return result;
13201336 }
13211337
1338 /** \test multiple http transactions and body chunks of request handling */
1339 static int DetectHttpClientBodyTest14(void) {
1340 int result = 0;
1341 Signature *s = NULL;
1342 DetectEngineThreadCtx *det_ctx = NULL;
1343 ThreadVars th_v;
1344 Flow f;
1345 TcpSession ssn;
1346 Packet *p = NULL;
1347 uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
1348 uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
1349 uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
1350 uint8_t httpbuf4[] = "Body one!!";
1351 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1352 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1353 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1354 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1355 uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
1356 uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
1357 uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
1358 uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
1359 uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
1360 uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
1361
1362 memset(&th_v, 0, sizeof(th_v));
1363 memset(&f, 0, sizeof(f));
1364 memset(&ssn, 0, sizeof(ssn));
1365
1366 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1367
1368 FLOW_INITIALIZE(&f);
1369 f.protoctx = (void *)&ssn;
1370 f.proto = IPPROTO_TCP;
1371 f.src.family = AF_INET;
1372 f.dst.family = AF_INET;
1373
1374 p->flow = &f;
1375 p->flowflags |= FLOW_PKT_TOSERVER;
1376 p->flowflags |= FLOW_PKT_ESTABLISHED;
1377 f.alproto = ALPROTO_HTTP;
1378
1379 StreamTcpInitConfig(TRUE);
1380 FlowL7DataPtrInit(&f);
1381
1382 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1383 if (de_ctx == NULL) {
1384 goto end;
1385 }
1386
1387 de_ctx->flags |= DE_QUIET;
1388
1389 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"one\"; http_client_body; sid:1; rev:1;)");
1390 if (s == NULL) {
1391 printf("sig parse failed: ");
1392 goto end;
1393 }
1394 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; content:\"two\"; http_client_body; sid:2; rev:1;)");
1395 if (s == NULL) {
1396 printf("sig2 parse failed: ");
1397 goto end;
1398 }
1399
1400 SigGroupBuild(de_ctx);
1401 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1402
1403 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
1404 if (r != 0) {
1405 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1406 goto end;
1407 }
1408
1409 /* do detect */
1410 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1411 if (PacketAlertCheck(p, 1)) {
1412 printf("sig 1 alerted: ");
1413 goto end;
1414 }
1415 p->alerts.cnt = 0;
1416
1417 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
1418 if (r != 0) {
1419 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1420 goto end;
1421 }
1422
1423 /* do detect */
1424 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1425 if (PacketAlertCheck(p, 1)) {
1426 printf("sig 1 alerted (2): ");
1427 goto end;
1428 }
1429 p->alerts.cnt = 0;
1430
1431 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3);
1432 if (r != 0) {
1433 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1434 goto end;
1435 }
1436
1437 /* do detect */
1438 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1439 if (PacketAlertCheck(p, 1)) {
1440 printf("signature matched, but shouldn't have: ");
1441 goto end;
1442 }
1443 p->alerts.cnt = 0;
1444
1445 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4);
1446 if (r != 0) {
1447 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
1448 result = 0;
1449 goto end;
1450 }
1451
1452 /* do detect */
1453 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1454 if (!(PacketAlertCheck(p, 1))) {
1455 printf("sig 1 didn't alert: ");
1456 goto end;
1457 }
1458 p->alerts.cnt = 0;
1459
1460 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5);
1461 if (r != 0) {
1462 printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
1463 goto end;
1464 }
1465
1466 /* do detect */
1467 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1468 if (PacketAlertCheck(p, 1)) {
1469 printf("sig 1 alerted (5): ");
1470 goto end;
1471 }
1472 p->alerts.cnt = 0;
1473
1474 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6);
1475 if (r != 0) {
1476 printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
1477 goto end;
1478 }
1479
1480 /* do detect */
1481 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1482 if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) {
1483 printf("sig 1 alerted (request 2, chunk 6): ");
1484 goto end;
1485 }
1486 p->alerts.cnt = 0;
1487
1488 SCLogDebug("sending data chunk 7");
1489
1490 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7);
1491 if (r != 0) {
1492 printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r);
1493 goto end;
1494 }
1495
1496 /* do detect */
1497 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1498 if (!(PacketAlertCheck(p, 2))) {
1499 printf("signature 2 didn't match, but should have: ");
1500 goto end;
1501 }
1502 p->alerts.cnt = 0;
1503
1504 HtpState *htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
1505 if (htp_state == NULL) {
1506 printf("no http state: ");
1507 result = 0;
1508 goto end;
1509 }
1510
1511 if (list_size(htp_state->connp->conn->transactions) != 2) {
1512 printf("The http app layer doesn't have 2 transactions, but it should: ");
1513 goto end;
1514 }
1515
1516 result = 1;
1517 end:
1518 if (det_ctx != NULL) {
1519 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1520 }
1521 if (de_ctx != NULL) {
1522 SigGroupCleanup(de_ctx);
1523 DetectEngineCtxFree(de_ctx);
1524 }
1525
1526 FlowL7DataPtrFree(&f);
1527 StreamTcpFreeConfig(TRUE);
1528 FLOW_DESTROY(&f);
1529 UTHFreePacket(p);
1530 return result;
1531 }
1532
1533 /** \test multiple http transactions and body chunks of request handling */
1534 static int DetectHttpClientBodyTest15(void) {
1535 int result = 0;
1536 Signature *s = NULL;
1537 DetectEngineThreadCtx *det_ctx = NULL;
1538 ThreadVars th_v;
1539 Flow f;
1540 TcpSession ssn;
1541 Packet *p = NULL;
1542 uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
1543 uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
1544 uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
1545 uint8_t httpbuf4[] = "Body one!!";
1546 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1547 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1548 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1549 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1550 uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
1551 uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
1552 uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
1553 uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
1554 uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
1555 uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
1556
1557 memset(&th_v, 0, sizeof(th_v));
1558 memset(&f, 0, sizeof(f));
1559 memset(&ssn, 0, sizeof(ssn));
1560
1561 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1562
1563 FLOW_INITIALIZE(&f);
1564 f.protoctx = (void *)&ssn;
1565 f.proto = IPPROTO_TCP;
1566 f.src.family = AF_INET;
1567 f.dst.family = AF_INET;
1568
1569 p->flow = &f;
1570 p->flowflags |= FLOW_PKT_TOSERVER;
1571 p->flowflags |= FLOW_PKT_ESTABLISHED;
1572 f.alproto = ALPROTO_HTTP;
1573
1574 StreamTcpInitConfig(TRUE);
1575 FlowL7DataPtrInit(&f);
1576
1577 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1578 if (de_ctx == NULL) {
1579 goto end;
1580 }
1581
1582 de_ctx->flags |= DE_QUIET;
1583
1584 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"one\"; http_client_body; sid:1; rev:1;)");
1585 if (s == NULL) {
1586 printf("sig parse failed: ");
1587 goto end;
1588 }
1589 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; content:\"two\"; http_client_body; sid:2; rev:1;)");
1590 if (s == NULL) {
1591 printf("sig2 parse failed: ");
1592 goto end;
1593 }
1594
1595 SigGroupBuild(de_ctx);
1596 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1597
1598 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
1599 if (r != 0) {
1600 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1601 goto end;
1602 }
1603
1604 /* do detect */
1605 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1606 if (PacketAlertCheck(p, 1)) {
1607 printf("sig 1 alerted: ");
1608 goto end;
1609 }
1610 p->alerts.cnt = 0;
1611
1612 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
1613 if (r != 0) {
1614 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1615 goto end;
1616 }
1617
1618 /* do detect */
1619 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1620 if (PacketAlertCheck(p, 1)) {
1621 printf("sig 1 alerted (2): ");
1622 goto end;
1623 }
1624 p->alerts.cnt = 0;
1625
1626 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3);
1627 if (r != 0) {
1628 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1629 goto end;
1630 }
1631
1632 /* do detect */
1633 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1634 if (PacketAlertCheck(p, 1)) {
1635 printf("signature matched, but shouldn't have: ");
1636 goto end;
1637 }
1638 p->alerts.cnt = 0;
1639
1640 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4);
1641 if (r != 0) {
1642 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
1643 result = 0;
1644 goto end;
1645 }
1646
1647 /* do detect */
1648 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1649 if (!(PacketAlertCheck(p, 1))) {
1650 printf("sig 1 didn't alert: ");
1651 goto end;
1652 }
1653 p->alerts.cnt = 0;
1654
1655 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5);
1656 if (r != 0) {
1657 printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
1658 goto end;
1659 }
1660
1661 /* do detect */
1662 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1663 if (PacketAlertCheck(p, 1)) {
1664 printf("sig 1 alerted (5): ");
1665 goto end;
1666 }
1667 p->alerts.cnt = 0;
1668
1669 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6);
1670 if (r != 0) {
1671 printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
1672 goto end;
1673 }
1674
1675 /* do detect */
1676 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1677 if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) {
1678 printf("sig 1 alerted (request 2, chunk 6): ");
1679 goto end;
1680 }
1681 p->alerts.cnt = 0;
1682
1683 SCLogDebug("sending data chunk 7");
1684
1685 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7);
1686 if (r != 0) {
1687 printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r);
1688 goto end;
1689 }
1690
1691 /* do detect */
1692 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1693 if (!(PacketAlertCheck(p, 2))) {
1694 printf("signature 2 didn't match, but should have: ");
1695 goto end;
1696 }
1697 p->alerts.cnt = 0;
1698
1699 HtpState *htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
1700 if (htp_state == NULL) {
1701 printf("no http state: ");
1702 result = 0;
1703 goto end;
1704 }
1705
1706 /* hardcoded check of the transactions and it's client body chunks */
1707 if (list_size(htp_state->connp->conn->transactions) != 2) {
1708 printf("The http app layer doesn't have 2 transactions, but it should: ");
1709 goto end;
1710 }
1711
1712 htp_tx_t *t1 = list_get(htp_state->connp->conn->transactions, 0);
1713 htp_tx_t *t2 = list_get(htp_state->connp->conn->transactions, 1);
1714
1715 SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(t1);
1716
1717 HtpBodyChunk *cur = htud->body.first;
1718 if (htud->body.nchunks == 0) {
1719 SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
1720 goto end;
1721 }
1722
1723 if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) {
1724 SCLogDebug("Body data in t1 is not correctly set: ");
1725 goto end;
1726 }
1727
1728 htud = (SCHtpTxUserData *) htp_tx_get_user_data(t2);
1729
1730 cur = htud->body.first;
1731 if (htud->body.nchunks == 0) {
1732 SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
1733 goto end;
1734 }
1735
1736 if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) {
1737 SCLogDebug("Body data in t1 is not correctly set: ");
1738 goto end;
1739 }
1740
1741 result = 1;
1742 end:
1743 if (det_ctx != NULL) {
1744 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1745 }
1746 if (de_ctx != NULL) {
1747 SigGroupCleanup(de_ctx);
1748 DetectEngineCtxFree(de_ctx);
1749 }
1750
1751 FlowL7DataPtrFree(&f);
1752 StreamTcpFreeConfig(TRUE);
1753 FLOW_DESTROY(&f);
1754 UTHFreePacket(p);
1755 return result;
1756 }
1757
1758
13221759 #endif /* UNITTESTS */
13231760
13241761 void DetectHttpClientBodyRegisterTests(void)
13371774 UtRegisterTest("DetectHttpClientBodyTest11", DetectHttpClientBodyTest11, 1);
13381775 UtRegisterTest("DetectHttpClientBodyTest12", DetectHttpClientBodyTest12, 1);
13391776 UtRegisterTest("DetectHttpClientBodyTest13", DetectHttpClientBodyTest13, 1);
1777 UtRegisterTest("DetectHttpClientBodyTest14", DetectHttpClientBodyTest14, 1);
1778 UtRegisterTest("DetectHttpClientBodyTest15", DetectHttpClientBodyTest15, 1);
13401779 #endif /* UNITTESTS */
13411780
13421781 return;
259259 /* flag the signature to indicate that we scan the app layer data */
260260 s->flags |= SIG_FLAG_APPLAYER;
261261 s->alproto = ALPROTO_HTTP;
262 /* enable http request body callback in the http app layer parser */
263 AppLayerHtpEnableRequestBodyCallback();
264262
265263 return 0;
266264
9797 htp_tx_t *tx = NULL;
9898 int ret = 0;
9999
100 if (hs == NULL) {
100 if (hs == NULL || hs->connp == NULL || hs->connp->conn == NULL) {
101101 SCLogDebug("No HTP state.");
102102 SCReturnInt(0);
103103 }
12431243 if (sig == NULL)
12441244 goto error;
12451245
1246 /* default gid to 1 */
1247 sig->gid = 1;
1248
12461249 if (SigParse(de_ctx, sig, sigstr, SIG_DIREC_NORMAL) < 0)
12471250 goto error;
12481251
13851388 /* XXX one day we will support this the way Snort does,
13861389 * through classifications.config */
13871390 sig->prio = 3;
1391 /* default gid to 1 */
1392 sig->gid = 1;
13881393
13891394 if (SigParse(de_ctx, sig, sigstr, SIG_DIREC_NORMAL) < 0)
13901395 goto error;
20612066 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
20622067 result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
20632068 de_ctx->sig_list->rev == 2);
2069 if (result == 0)
2070 goto end;
20642071 result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
20652072 de_ctx->sig_list->next->rev == 6);
20662073 if (result == 0)
20692076 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)");
20702077 result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
20712078 de_ctx->sig_list->rev == 4);
2079 if (result == 0)
2080 goto end;
20722081 result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
20732082 de_ctx->sig_list->next->rev == 6);
20742083 if (result == 0)
7878
7979 int DetectPcreMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *);
8080 int DetectPcreALMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m);
81 int DetectPcreALMatchCookie(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m);
82 int DetectPcreALMatchHeader(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m);
83 int DetectPcreALMatchMethod(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m);
8184 static int DetectPcreSetup (DetectEngineCtx *, Signature *, char *);
8285 void DetectPcreFree(void *);
8386 void DetectPcreRegisterTests(void);
103106 sigmatch_table[DETECT_PCRE_HTTPBODY].Setup = NULL;
104107 sigmatch_table[DETECT_PCRE_HTTPBODY].Free = DetectPcreFree;
105108 sigmatch_table[DETECT_PCRE_HTTPBODY].RegisterTests = NULL;
106
107109 sigmatch_table[DETECT_PCRE_HTTPBODY].flags |= SIGMATCH_PAYLOAD;
110
111 /* The same for Cookie, Method and Header */
112 sigmatch_table[DETECT_PCRE_HTTPCOOKIE].name = "__pcre_http_cookie__"; /* not a real keyword */
113 sigmatch_table[DETECT_PCRE_HTTPCOOKIE].Match = NULL;
114 sigmatch_table[DETECT_PCRE_HTTPCOOKIE].AppLayerMatch = DetectPcreALMatchCookie;
115 sigmatch_table[DETECT_PCRE_HTTPCOOKIE].alproto = ALPROTO_HTTP;
116 sigmatch_table[DETECT_PCRE_HTTPCOOKIE].Setup = NULL;
117 sigmatch_table[DETECT_PCRE_HTTPCOOKIE].Free = DetectPcreFree;
118 sigmatch_table[DETECT_PCRE_HTTPCOOKIE].RegisterTests = NULL;
119 sigmatch_table[DETECT_PCRE_HTTPCOOKIE].flags |= SIGMATCH_PAYLOAD;
120
121 sigmatch_table[DETECT_PCRE_HTTPMETHOD].name = "__pcre_http_method__"; /* not a real keyword */
122 sigmatch_table[DETECT_PCRE_HTTPMETHOD].Match = NULL;
123 sigmatch_table[DETECT_PCRE_HTTPMETHOD].AppLayerMatch = DetectPcreALMatchMethod;
124 sigmatch_table[DETECT_PCRE_HTTPMETHOD].alproto = ALPROTO_HTTP;
125 sigmatch_table[DETECT_PCRE_HTTPMETHOD].Setup = NULL;
126 sigmatch_table[DETECT_PCRE_HTTPMETHOD].Free = DetectPcreFree;
127 sigmatch_table[DETECT_PCRE_HTTPMETHOD].RegisterTests = NULL;
128 sigmatch_table[DETECT_PCRE_HTTPMETHOD].flags |= SIGMATCH_PAYLOAD;
129
130 sigmatch_table[DETECT_PCRE_HTTPHEADER].name = "__pcre_http_header__"; /* not a real keyword */
131 sigmatch_table[DETECT_PCRE_HTTPHEADER].Match = NULL;
132 sigmatch_table[DETECT_PCRE_HTTPHEADER].AppLayerMatch = DetectPcreALMatchHeader;
133 sigmatch_table[DETECT_PCRE_HTTPHEADER].alproto = ALPROTO_HTTP;
134 sigmatch_table[DETECT_PCRE_HTTPHEADER].Setup = NULL;
135 sigmatch_table[DETECT_PCRE_HTTPHEADER].Free = DetectPcreFree;
136 sigmatch_table[DETECT_PCRE_HTTPHEADER].RegisterTests = NULL;
137 sigmatch_table[DETECT_PCRE_HTTPHEADER].flags |= SIGMATCH_PAYLOAD;
138
108139
109140 const char *eb;
110141 int eo;
160191 error:
161192 /* XXX */
162193 return;
194 }
195
196 /**
197 * \brief Match a regex on data sent at an http method (needs the l7 parser).
198 *
199 * \param det_ctx Thread detection ctx.
200 * \param s Signature.
201 * \param sm SigMatch to match against.
202 * \param data Data to match against.
203 * \param data_len Data length.
204 *
205 * \retval 1: match
206 * \retval 0: no match
207 */
208 int DetectPcreALDoMatchMethod(DetectEngineThreadCtx *det_ctx, Signature *s,
209 SigMatch *m, Flow *f, uint8_t flags,
210 void *state)
211 {
212 SCEnter();
213
214 int ret = 0;
215 int toret = 0;
216 size_t idx;
217
218 #define MAX_SUBSTRINGS 30
219 int ov[MAX_SUBSTRINGS];
220 uint8_t *ptr = NULL;
221 uint16_t len = 0;
222
223 DetectPcreData *pe = (DetectPcreData *)m->ctx;
224
225 /* define ptr & len */
226 SCMutexLock(&f->m);
227 SCLogDebug("got lock %p", &f->m);
228
229 HtpState *htp_state = (HtpState *)state;
230 if (htp_state == NULL) {
231 SCLogDebug("no HTTP layer state has been received, so no match");
232 goto end;
233 }
234
235 if (!(htp_state->flags & HTP_FLAG_STATE_OPEN)) {
236 SCLogDebug("HTP state not yet properly setup, so no match");
237 goto end;
238 }
239
240 SCLogDebug("htp_state %p, flow %p", htp_state, f);
241 SCLogDebug("htp_state->connp %p", htp_state->connp);
242 SCLogDebug("htp_state->connp->conn %p", htp_state->connp->conn);
243
244 if (htp_state->connp == NULL || htp_state->connp->conn == NULL) {
245 SCLogDebug("HTTP connection structure is NULL");
246 goto end;
247 }
248
249 htp_tx_t *tx = NULL;
250
251 for (idx = 0;//htp_state->new_in_tx_index;
252 idx < list_size(htp_state->connp->conn->transactions); idx++)
253 {
254 tx = list_get(htp_state->connp->conn->transactions, idx);
255 if (tx == NULL)
256 continue;
257
258 ptr = (uint8_t *) bstr_ptr(tx->request_method);
259 len = bstr_size(tx->request_method);
260 if (ptr == NULL)
261 continue;
262
263 //printf("Matching Method");
264 //PrintRawUriFp(stdout, (uint8_t*)ptr, len);
265
266 /* run the actual pcre detection */
267 ret = pcre_exec(pe->re, pe->sd, (char *)ptr, len, 0, 0, ov, MAX_SUBSTRINGS);
268 SCLogDebug("ret %d (negating %s)", ret, pe->negate ? "set" : "not set");
269
270 if (ret == PCRE_ERROR_NOMATCH) {
271 if (pe->negate == 1) {
272 /* regex didn't match with negate option means we
273 * consider it a match */
274 ret = 1;
275 toret |= ret;
276 break;
277 } else {
278 ret = 0;
279 }
280 toret |= ret;
281 } else if (ret >= 0) {
282 if (pe->negate == 1) {
283 /* regex matched but we're negated, so not
284 * considering it a match */
285 ret = 0;
286 } else {
287 /* regex matched and we're not negated,
288 * considering it a match */
289 ret = 1;
290 toret |= ret;
291 break;
292 }
293 } else {
294 SCLogDebug("pcre had matching error");
295 ret = 0;
296 }
297 }
298
299 end:
300 SCMutexUnlock(&f->m);
301 SCLogDebug("released lock %p", &f->m);
302
303 SCReturnInt(toret);
304 }
305
306 /**
307 * \brief Match a regex on data sent at an http header (needs the l7 parser).
308 *
309 * \param det_ctx Thread detection ctx.
310 * \param s Signature.
311 * \param sm SigMatch to match against.
312 * \param data Data to match against.
313 * \param data_len Data length.
314 *
315 * \retval 1: match
316 * \retval 0: no match
317 */
318 int DetectPcreALDoMatchHeader(DetectEngineThreadCtx *det_ctx, Signature *s,
319 SigMatch *m, Flow *f, uint8_t flags,
320 void *state)
321 {
322 SCEnter();
323
324 int ret = 0;
325 int toret = 0;
326 size_t idx;
327
328 #define MAX_SUBSTRINGS 30
329 int ov[MAX_SUBSTRINGS];
330 uint8_t *ptr = NULL;
331 uint16_t len = 0;
332
333 DetectPcreData *pe = (DetectPcreData *)m->ctx;
334
335 /* define ptr & len */
336 SCMutexLock(&f->m);
337 SCLogDebug("got lock %p", &f->m);
338
339 HtpState *htp_state = (HtpState *)state;
340 if (htp_state == NULL) {
341 SCLogDebug("no HTTP layer state has been received, so no match");
342 goto end;
343 }
344
345 if (!(htp_state->flags & HTP_FLAG_STATE_OPEN)) {
346 SCLogDebug("HTP state not yet properly setup, so no match");
347 goto end;
348 }
349
350 SCLogDebug("htp_state %p, flow %p", htp_state, f);
351 SCLogDebug("htp_state->connp %p", htp_state->connp);
352 SCLogDebug("htp_state->connp->conn %p", htp_state->connp->conn);
353
354 if (htp_state->connp == NULL || htp_state->connp->conn == NULL) {
355 SCLogDebug("HTTP connection structure is NULL");
356 goto end;
357 }
358
359 htp_tx_t *tx = NULL;
360 bstr *headers = NULL;
361
362 for (idx = 0;//htp_state->new_in_tx_index;
363 idx < list_size(htp_state->connp->conn->transactions); idx++)
364 {
365 tx = list_get(htp_state->connp->conn->transactions, idx);
366 if (tx == NULL)
367 continue;
368
369 SCLogDebug("inspecting tx %p", tx);
370
371 headers = htp_tx_get_request_headers_raw(tx);
372 if (headers == NULL)
373 continue;
374
375 ptr = (uint8_t *)bstr_ptr(headers);
376 len = bstr_len(headers);
377 if (ptr == NULL)
378 continue;
379
380 //printf("Matching Header");
381 //PrintRawUriFp(stdout, (uint8_t*)ptr, len);
382
383 /* run the actual pcre detection */
384 ret = pcre_exec(pe->re, pe->sd, (char *)ptr, len, 0, 0, ov, MAX_SUBSTRINGS);
385 SCLogDebug("ret %d (negating %s)", ret, pe->negate ? "set" : "not set");
386
387 if (ret == PCRE_ERROR_NOMATCH) {
388 if (pe->negate == 1) {
389 /* regex didn't match with negate option means we
390 * consider it a match */
391 ret = 1;
392 toret |= ret;
393 break;
394 } else {
395 ret = 0;
396 }
397 toret |= ret;
398 } else if (ret >= 0) {
399 if (pe->negate == 1) {
400 /* regex matched but we're negated, so not
401 * considering it a match */
402 ret = 0;
403 } else {
404 /* regex matched and we're not negated,
405 * considering it a match */
406 ret = 1;
407 toret |= ret;
408 break;
409 }
410 } else {
411 SCLogDebug("pcre had matching error");
412 ret = 0;
413 }
414 }
415
416 end:
417 SCMutexUnlock(&f->m);
418 SCLogDebug("released lock %p", &f->m);
419
420 SCReturnInt(toret);
421 }
422
423 /**
424 * \brief Match a regex on data sent at an http cookie (needs the l7 parser).
425 *
426 * \param det_ctx Thread detection ctx.
427 * \param s Signature.
428 * \param sm SigMatch to match against.
429 * \param data Data to match against.
430 * \param data_len Data length.
431 *
432 * \retval 1: match
433 * \retval 0: no match
434 */
435 int DetectPcreALDoMatchCookie(DetectEngineThreadCtx *det_ctx, Signature *s,
436 SigMatch *m, Flow *f, uint8_t flags,
437 void *state)
438 {
439 SCEnter();
440
441 int ret = 0;
442 int toret = 0;
443 size_t idx;
444
445 #define MAX_SUBSTRINGS 30
446 int ov[MAX_SUBSTRINGS];
447 uint8_t *ptr = NULL;
448 uint16_t len = 0;
449
450 DetectPcreData *pe = (DetectPcreData *)m->ctx;
451
452 /* define ptr & len */
453 SCMutexLock(&f->m);
454 SCLogDebug("got lock %p", &f->m);
455
456 HtpState *htp_state = (HtpState *)state;
457 if (htp_state == NULL) {
458 SCLogDebug("no HTTP layer state has been received, so no match");
459 goto end;
460 }
461
462 if (!(htp_state->flags & HTP_FLAG_STATE_OPEN)) {
463 SCLogDebug("HTP state not yet properly setup, so no match");
464 goto end;
465 }
466
467 SCLogDebug("htp_state %p, flow %p", htp_state, f);
468 SCLogDebug("htp_state->connp %p", htp_state->connp);
469 SCLogDebug("htp_state->connp->conn %p", htp_state->connp->conn);
470
471 if (htp_state->connp == NULL || htp_state->connp->conn == NULL) {
472 SCLogDebug("HTTP connection structure is NULL");
473 goto end;
474 }
475
476 htp_tx_t *tx = NULL;
477
478 for (idx = 0;//htp_state->new_in_tx_index;
479 idx < list_size(htp_state->connp->conn->transactions); idx++)
480 {
481 tx = list_get(htp_state->connp->conn->transactions, idx);
482 if (tx == NULL)
483 continue;
484
485 htp_header_t *h = NULL;
486 h = (htp_header_t *) table_getc(tx->request_headers, "Cookie");
487 if (h == NULL) {
488 SCLogDebug("no HTTP Cookie header in the received request");
489 goto end;
490 }
491 ptr = (uint8_t *) bstr_ptr(h->value);
492 len = bstr_size(h->value);
493
494 if (ptr == NULL)
495 continue;
496
497 //printf("Matching Cookie");
498 //PrintRawUriFp(stdout, (uint8_t*)ptr, len);
499
500 SCLogDebug("we have a cookie header");
501
502 /* run the actual pcre detection */
503 ret = pcre_exec(pe->re, pe->sd, (char *)ptr, len, 0, 0, ov, MAX_SUBSTRINGS);
504 SCLogDebug("ret %d (negating %s)", ret, pe->negate ? "set" : "not set");
505
506 if (ret == PCRE_ERROR_NOMATCH) {
507 if (pe->negate == 1) {
508 /* regex didn't match with negate option means we
509 * consider it a match */
510 ret = 1;
511 toret |= ret;
512 break;
513 } else {
514 ret = 0;
515 }
516 toret |= ret;
517 } else if (ret >= 0) {
518 if (pe->negate == 1) {
519 /* regex matched but we're negated, so not
520 * considering it a match */
521 ret = 0;
522 } else {
523 /* regex matched and we're not negated,
524 * considering it a match */
525 ret = 1;
526 toret |= ret;
527 break;
528 }
529 } else {
530 SCLogDebug("pcre had matching error");
531 if (pe->negate == 1) {
532 ret = 1;
533 toret |= ret;
534 break;
535 } else {
536 ret = 0;
537 }
538 toret |= ret;
539 }
540 }
541
542 end:
543 SCMutexUnlock(&f->m);
544 SCLogDebug("released lock %p", &f->m);
545
546 SCReturnInt(toret);
163547 }
164548
165549 int DetectPcreALDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *m, Flow *f, uint8_t flags, void *state) {
182566 if (htp_state == NULL) {
183567 SCLogDebug("No htp state, no match at http body data");
184568 goto unlock;
185 } else if (htp_state->body.nchunks == 0) {
186 SCLogDebug("No body data to inspect");
187 goto unlock;
188 } else {
189 pcreret = 0;
190 int wspace[255];
191 int flags = PCRE_PARTIAL;
192
193 HtpBodyChunk *cur = htp_state->body.first;
194 if (cur == NULL) {
195 SCLogDebug("No body chunks to inspect");
569 }
570
571 htp_tx_t *tx = NULL;
572 size_t idx = 0;
573
574 for (idx = 0;//hs->new_in_tx_index;
575 idx < list_size(htp_state->connp->conn->transactions); idx++)
576 {
577 tx = list_get(htp_state->connp->conn->transactions, idx);
578 if (tx == NULL)
579 continue;
580
581 SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(tx);
582 if (htud == NULL)
583 continue;
584
585 HtpBodyChunk *cur = htud->body.first;
586 if (htud->body.nchunks == 0) {
587 SCLogDebug("No body data to inspect");
196588 goto unlock;
197 }
198 htp_state->body.pcre_flags |= HTP_PCRE_DONE;
199
200 while (cur != NULL) {
201 if (SCLogDebugEnabled()) {
202 printf("\n");
203 PrintRawUriFp(stdout, (uint8_t*)cur->data, cur->len);
204 printf("\n");
589 } else {
590 pcreret = 0;
591 int wspace[255];
592 int flags = PCRE_PARTIAL;
593
594 if (cur == NULL) {
595 SCLogDebug("No body chunks to inspect");
596 goto unlock;
205597 }
206 pcreret = pcre_dfa_exec(pe->re, NULL, (char*)cur->data, cur->len, 0,
207 flags|PCRE_DFA_SHORTEST, ov, MAX_SUBSTRINGS,
208 wspace, MAX_SUBSTRINGS);
209 cur = cur->next;
210
211 SCLogDebug("Pcre Ret %d", pcreret);
212 switch (pcreret) {
213 case PCRE_ERROR_PARTIAL:
214 /* make pcre to use the working space of the last partial
215 * match, (match over multiple chunks)
216 */
217 SCLogDebug("partial match");
218 flags |= PCRE_DFA_RESTART;
219 htp_state->body.pcre_flags |= HTP_PCRE_HAS_MATCH;
220 break;
221 case PCRE_ERROR_NOMATCH:
222 SCLogDebug("no match");
223 flags = PCRE_PARTIAL;
224 break;
225 case 0:
226 SCLogDebug("Perfect Match!");
227 ret = 1;
228 goto unlock;
229 break;
230 default:
231 if (pcreret > 0) {
232 SCLogDebug("Match with captured data");
598 htud->body.pcre_flags |= HTP_PCRE_DONE;
599
600 while (cur != NULL) {
601 if (SCLogDebugEnabled()) {
602 printf("\n");
603 PrintRawUriFp(stdout, (uint8_t*)cur->data, cur->len);
604 printf("\n");
605 }
606 pcreret = pcre_dfa_exec(pe->re, NULL, (char*)cur->data, cur->len, 0,
607 flags|PCRE_DFA_SHORTEST, ov, MAX_SUBSTRINGS,
608 wspace, MAX_SUBSTRINGS);
609 cur = cur->next;
610
611 SCLogDebug("Pcre Ret %d", pcreret);
612 switch (pcreret) {
613 case PCRE_ERROR_PARTIAL:
614 /* make pcre to use the working space of the last partial
615 * match, (match over multiple chunks)
616 */
617 SCLogDebug("partial match");
618 flags |= PCRE_DFA_RESTART;
619 htud->body.pcre_flags |= HTP_PCRE_HAS_MATCH;
620 break;
621 case PCRE_ERROR_NOMATCH:
622 SCLogDebug("no match");
623 flags = PCRE_PARTIAL;
624 break;
625 case 0:
626 SCLogDebug("Perfect Match!");
233627 ret = 1;
234 } else {
235 SCLogDebug("No match, pcre failed");
236 ret = 0;
237 }
238 goto unlock;
628 goto unlock;
629 break;
630 default:
631 if (pcreret > 0) {
632 SCLogDebug("Match with captured data");
633 ret = 1;
634 } else {
635 SCLogDebug("No match, pcre failed");
636 ret = 0;
637 }
638 goto unlock;
639 }
239640 }
240641 }
241642 }
259660 uint8_t flags, void *state, Signature *s, SigMatch *m)
260661 {
261662 int r = DetectPcreALDoMatch(det_ctx, s, m, f, flags, state);
663 SCReturnInt(r);
664 }
665
666 /**
667 * \brief match the specified pcre at http header, requesting it from htp/L7
668 *
669 * \param t pointer to thread vars
670 * \param det_ctx pointer to the pattern matcher thread
671 * \param p pointer to the current packet
672 * \param m pointer to the sigmatch that we will cast into DetectPcreData
673 *
674 * \retval int 0 no match; 1 match
675 */
676 int DetectPcreALMatchHeader(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f,
677 uint8_t flags, void *state, Signature *s, SigMatch *m)
678 {
679 int r = DetectPcreALDoMatchHeader(det_ctx, s, m, f, flags, state);
680 SCReturnInt(r);
681 }
682
683 /**
684 * \brief match the specified pcre at http method, requesting it from htp/L7
685 *
686 * \param t pointer to thread vars
687 * \param det_ctx pointer to the pattern matcher thread
688 * \param p pointer to the current packet
689 * \param m pointer to the sigmatch that we will cast into DetectPcreData
690 *
691 * \retval int 0 no match; 1 match
692 */
693 int DetectPcreALMatchMethod(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f,
694 uint8_t flags, void *state, Signature *s, SigMatch *m)
695 {
696 int r = DetectPcreALDoMatchMethod(det_ctx, s, m, f, flags, state);
697 SCReturnInt(r);
698 }
699
700 /**
701 * \brief match the specified pcre at http cookie, requesting it from htp/L7
702 *
703 * \param t pointer to thread vars
704 * \param det_ctx pointer to the pattern matcher thread
705 * \param p pointer to the current packet
706 * \param m pointer to the sigmatch that we will cast into DetectPcreData
707 *
708 * \retval int 0 no match; 1 match
709 */
710 int DetectPcreALMatchCookie(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f,
711 uint8_t flags, void *state, Signature *s, SigMatch *m)
712 {
713 int r = DetectPcreALDoMatchCookie(det_ctx, s, m, f, flags, state);
262714 SCReturnInt(r);
263715 }
264716
6621114 case 'U': /* snort's option */
6631115 pd->flags |= DETECT_PCRE_URI;
6641116 break;
1117 case 'H': /* snort's option */
1118 pd->flags |= DETECT_PCRE_HEADER;
1119 break;
1120 case 'M': /* snort's option */
1121 pd->flags |= DETECT_PCRE_METHOD;
1122 break;
1123 case 'C': /* snort's option */
1124 pd->flags |= DETECT_PCRE_COOKIE;
1125 break;
6651126 case 'O':
6661127 pd->flags |= DETECT_PCRE_MATCH_LIMIT;
6671128 break;
8111272 switch (s->alproto) {
8121273 case ALPROTO_DCERPC:
8131274 if ( (pd->flags & DETECT_PCRE_URI) ||
1275 (pd->flags & DETECT_PCRE_METHOD) ||
1276 (pd->flags & DETECT_PCRE_HEADER) ||
1277 (pd->flags & DETECT_PCRE_COOKIE) ||
8141278 (pd->flags & DETECT_PCRE_HTTP_BODY_AL) ) {
8151279 SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. "
8161280 "DCERPC rule has pcre keyword with http related modifier.");
8331297 sm->type = DETECT_PCRE;
8341298 sm->ctx = (void *)pd;
8351299
836 if (pd->flags & DETECT_PCRE_HTTP_BODY_AL) {
1300 if (pd->flags & DETECT_PCRE_HEADER) {
1301 sm->type = DETECT_PCRE_HTTPHEADER;
1302
1303 SCLogDebug("Header inspection modifier set");
1304 s->flags |= SIG_FLAG_APPLAYER;
1305
1306 SigMatchAppendAppLayer(s, sm);
1307 } else if (pd->flags & DETECT_PCRE_COOKIE) {
1308 sm->type = DETECT_PCRE_HTTPCOOKIE;
1309
1310 SCLogDebug("Cookie inspection modifier set");
1311 s->flags |= SIG_FLAG_APPLAYER;
1312
1313 SigMatchAppendAppLayer(s, sm);
1314 } else if (pd->flags & DETECT_PCRE_METHOD) {
1315 sm->type = DETECT_PCRE_HTTPMETHOD;
1316
1317 SCLogDebug("Method inspection modifier set");
1318 s->flags |= SIG_FLAG_APPLAYER;
1319
1320 SigMatchAppendAppLayer(s, sm);
1321 } else if (pd->flags & DETECT_PCRE_HTTP_BODY_AL) {
8371322 sm->type = DETECT_PCRE_HTTPBODY;
8381323
8391324 SCLogDebug("Body inspection modifier set");
12911776 TcpSession ssn;
12921777 Packet *p = NULL;
12931778 ThreadVars th_v;
1294 DetectEngineThreadCtx *det_ctx;
1779 DetectEngineThreadCtx *det_ctx = NULL;
12951780 int result = 0;
12961781 Flow f;
12971782
17202205 /* do detect for p1 */
17212206 SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
17222207
2208 HtpState *http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
2209 if (http_state == NULL) {
2210 printf("no http state: ");
2211 result = 0;
2212 goto end;
2213 }
2214
2215 if (!(PacketAlertCheck(p1, 1))) {
2216 printf("sid 1 didn't match on p1 but should have: ");
2217 goto end;
2218 }
2219
2220 if (PacketAlertCheck(p1, 2)) {
2221 printf("sid 2 did match on p1 but shouldn't have: ");
2222 /* It's a partial match over 2 chunks*/
2223 goto end;
2224 }
2225
17232226 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
17242227 if (r != 0) {
17252228 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
17272230 goto end;
17282231 }
17292232
1730 HtpState *http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
1731 if (http_state == NULL) {
1732 printf("no http state: ");
1733 result = 0;
1734 goto end;
1735 }
1736
17372233 /* do detect for p2 */
17382234 SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
1739
1740 if (!(PacketAlertCheck(p1, 1))) {
1741 printf("sid 1 didn't match on p1 but should have: ");
1742 goto end;
1743 }
1744
1745 if (PacketAlertCheck(p1, 2)) {
1746 printf("sid 2 did match on p1 but shouldn't have: ");
1747 /* It's a partial match over 2 chunks*/
1748 goto end;
1749 }
17502235
17512236 if ((PacketAlertCheck(p2, 1))) {
17522237 printf("sid 1 did match on p2 but should have: ");
18302315 end:
18312316 if (p != NULL)
18322317 UTHFreePacket(p);
2318 return result;
2319 }
2320
2321 /** \test Check the signature working to alert when cookie modifier is
2322 * passed to pcre
2323 */
2324 static int DetectPcreTestSig09(void) {
2325 int result = 0;
2326 Flow f;
2327 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"
2328 "Cookie: dummy\r\n\r\n";
2329 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2330 TcpSession ssn;
2331 Packet *p = NULL;
2332 Signature *s = NULL;
2333 ThreadVars th_v;
2334 DetectEngineThreadCtx *det_ctx = NULL;
2335 HtpState *http_state = NULL;
2336
2337 memset(&th_v, 0, sizeof(th_v));
2338 memset(&p, 0, sizeof(p));
2339 memset(&f, 0, sizeof(f));
2340 memset(&ssn, 0, sizeof(ssn));
2341
2342 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
2343
2344 FLOW_INITIALIZE(&f);
2345 f.protoctx = (void *)&ssn;
2346 f.src.family = AF_INET;
2347 f.dst.family = AF_INET;
2348
2349 p->flow = &f;
2350 p->flowflags |= FLOW_PKT_TOSERVER;
2351 p->flowflags |= FLOW_PKT_ESTABLISHED;
2352 f.alproto = ALPROTO_HTTP;
2353
2354 StreamTcpInitConfig(TRUE);
2355 FlowL7DataPtrInit(&f);
2356
2357 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2358 if (de_ctx == NULL) {
2359 goto end;
2360 }
2361
2362 de_ctx->flags |= DE_QUIET;
2363
2364 s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:"
2365 "\"HTTP cookie\"; pcre:\"/dummy/C\"; "
2366 " sid:1;)");
2367 if (s == NULL) {
2368 printf("sig parse failed: ");
2369 goto end;
2370 }
2371
2372 SigGroupBuild(de_ctx);
2373 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2374
2375 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
2376 if (r != 0) {
2377 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2378 goto end;
2379 }
2380
2381 http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
2382 if (http_state == NULL) {
2383 printf("no http state: ");
2384 goto end;
2385 }
2386
2387 /* do detect */
2388 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2389
2390 if (!PacketAlertCheck(p, 1)) {
2391 printf("sig 1 failed to match: ");
2392 goto end;
2393 }
2394
2395 result = 1;
2396 end:
2397 if (det_ctx != NULL) {
2398 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2399 }
2400 if (de_ctx != NULL) {
2401 SigGroupCleanup(de_ctx);
2402 DetectEngineCtxFree(de_ctx);
2403 }
2404
2405 FlowL7DataPtrFree(&f);
2406 StreamTcpFreeConfig(TRUE);
2407 UTHFreePackets(&p, 1);
2408 return result;
2409 }
2410
2411 /** \test Check the signature working to alert when cookie modifier is
2412 * passed to a negated pcre
2413 */
2414 static int DetectPcreTestSig10(void) {
2415 int result = 0;
2416 Flow f;
2417 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"
2418 "Cookie: dummoOOooooO\r\n\r\n";
2419 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2420 TcpSession ssn;
2421 Packet *p = NULL;
2422 Signature *s = NULL;
2423 ThreadVars th_v;
2424 DetectEngineThreadCtx *det_ctx = NULL;
2425 HtpState *http_state = NULL;
2426
2427 memset(&th_v, 0, sizeof(th_v));
2428 memset(&p, 0, sizeof(p));
2429 memset(&f, 0, sizeof(f));
2430 memset(&ssn, 0, sizeof(ssn));
2431
2432 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
2433
2434 FLOW_INITIALIZE(&f);
2435 f.protoctx = (void *)&ssn;
2436 f.src.family = AF_INET;
2437 f.dst.family = AF_INET;
2438
2439 p->flow = &f;
2440 p->flowflags |= FLOW_PKT_TOSERVER;
2441 p->flowflags |= FLOW_PKT_ESTABLISHED;
2442 f.alproto = ALPROTO_HTTP;
2443
2444 StreamTcpInitConfig(TRUE);
2445 FlowL7DataPtrInit(&f);
2446
2447 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2448 if (de_ctx == NULL) {
2449 goto end;
2450 }
2451
2452 de_ctx->flags |= DE_QUIET;
2453
2454 s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:"
2455 "\"HTTP cookie\"; pcre:!\"/dummy/C\"; "
2456 " sid:1;)");
2457 if (s == NULL) {
2458 printf("sig parse failed: ");
2459 goto end;
2460 }
2461
2462 SigGroupBuild(de_ctx);
2463 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2464
2465 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
2466 if (r != 0) {
2467 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2468 goto end;
2469 }
2470
2471 http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
2472 if (http_state == NULL) {
2473 printf("no http state: ");
2474 goto end;
2475 }
2476
2477 /* do detect */
2478 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2479
2480 if (!PacketAlertCheck(p, 1)) {
2481 printf("sig 1 should match: ");
2482 goto end;
2483 }
2484
2485 result = 1;
2486 end:
2487 if (det_ctx != NULL) {
2488 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2489 }
2490 if (de_ctx != NULL) {
2491 SigGroupCleanup(de_ctx);
2492 DetectEngineCtxFree(de_ctx);
2493 }
2494
2495 FlowL7DataPtrFree(&f);
2496 StreamTcpFreeConfig(TRUE);
2497 UTHFreePackets(&p, 1);
2498 return result;
2499 }
2500
2501 /** \test Check the signature working to alert when method modifier is
2502 * passed to pcre
2503 */
2504 static int DetectPcreTestSig11(void) {
2505 int result = 0;
2506 Flow f;
2507 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"
2508 "Cookie: dummy\r\n\r\n";
2509 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2510 TcpSession ssn;
2511 Packet *p = NULL;
2512 Signature *s = NULL;
2513 ThreadVars th_v;
2514 DetectEngineThreadCtx *det_ctx = NULL;
2515 HtpState *http_state = NULL;
2516
2517 memset(&th_v, 0, sizeof(th_v));
2518 memset(&p, 0, sizeof(p));
2519 memset(&f, 0, sizeof(f));
2520 memset(&ssn, 0, sizeof(ssn));
2521
2522 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
2523
2524 FLOW_INITIALIZE(&f);
2525 f.protoctx = (void *)&ssn;
2526 f.src.family = AF_INET;
2527 f.dst.family = AF_INET;
2528
2529 p->flow = &f;
2530 p->flowflags |= FLOW_PKT_TOSERVER;
2531 p->flowflags |= FLOW_PKT_ESTABLISHED;
2532 f.alproto = ALPROTO_HTTP;
2533
2534 StreamTcpInitConfig(TRUE);
2535 FlowL7DataPtrInit(&f);
2536
2537 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2538 if (de_ctx == NULL) {
2539 goto end;
2540 }
2541
2542 de_ctx->flags |= DE_QUIET;
2543
2544 s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:"
2545 "\"HTTP method\"; pcre:\"/POST/M\"; "
2546 " sid:1;)");
2547 if (s == NULL) {
2548 printf("sig parse failed: ");
2549 goto end;
2550 }
2551
2552 SigGroupBuild(de_ctx);
2553 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2554
2555 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
2556 if (r != 0) {
2557 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2558 goto end;
2559 }
2560
2561 http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
2562 if (http_state == NULL) {
2563 printf("no http state: ");
2564 goto end;
2565 }
2566
2567 /* do detect */
2568 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2569
2570 if (!PacketAlertCheck(p, 1)) {
2571 printf("sig 1 failed to match: ");
2572 goto end;
2573 }
2574
2575 result = 1;
2576 end:
2577 if (det_ctx != NULL) {
2578 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2579 }
2580 if (de_ctx != NULL) {
2581 SigGroupCleanup(de_ctx);
2582 DetectEngineCtxFree(de_ctx);
2583 }
2584
2585 FlowL7DataPtrFree(&f);
2586 StreamTcpFreeConfig(TRUE);
2587 UTHFreePackets(&p, 1);
2588 return result;
2589 }
2590
2591 /** \test Check the signature working to alert when method modifier is
2592 * passed to a negated pcre
2593 */
2594 static int DetectPcreTestSig12(void) {
2595 int result = 0;
2596 Flow f;
2597 uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"
2598 "Cookie: dummoOOooooO\r\n\r\n";
2599 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2600 TcpSession ssn;
2601 Packet *p = NULL;
2602 Signature *s = NULL;
2603 ThreadVars th_v;
2604 DetectEngineThreadCtx *det_ctx = NULL;
2605 HtpState *http_state = NULL;
2606
2607 memset(&th_v, 0, sizeof(th_v));
2608 memset(&p, 0, sizeof(p));
2609 memset(&f, 0, sizeof(f));
2610 memset(&ssn, 0, sizeof(ssn));
2611
2612 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
2613
2614 FLOW_INITIALIZE(&f);
2615 f.protoctx = (void *)&ssn;
2616 f.src.family = AF_INET;
2617 f.dst.family = AF_INET;
2618
2619 p->flow = &f;
2620 p->flowflags |= FLOW_PKT_TOSERVER;
2621 p->flowflags |= FLOW_PKT_ESTABLISHED;
2622 f.alproto = ALPROTO_HTTP;
2623
2624 StreamTcpInitConfig(TRUE);
2625 FlowL7DataPtrInit(&f);
2626
2627 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2628 if (de_ctx == NULL) {
2629 goto end;
2630 }
2631
2632 de_ctx->flags |= DE_QUIET;
2633
2634 s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:"
2635 "\"HTTP method\"; pcre:!\"/POST/M\"; "
2636 " sid:1;)");
2637 if (s == NULL) {
2638 printf("sig parse failed: ");
2639 goto end;
2640 }
2641
2642 SigGroupBuild(de_ctx);
2643 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2644
2645 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
2646 if (r != 0) {
2647 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2648 goto end;
2649 }
2650
2651 http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
2652 if (http_state == NULL) {
2653 printf("no http state: ");
2654 goto end;
2655 }
2656
2657 /* do detect */
2658 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2659
2660 if (!PacketAlertCheck(p, 1)) {
2661 printf("sig 1 should match: ");
2662 goto end;
2663 }
2664
2665 result = 1;
2666 end:
2667 if (det_ctx != NULL) {
2668 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2669 }
2670 if (de_ctx != NULL) {
2671 SigGroupCleanup(de_ctx);
2672 DetectEngineCtxFree(de_ctx);
2673 }
2674
2675 FlowL7DataPtrFree(&f);
2676 StreamTcpFreeConfig(TRUE);
2677 UTHFreePackets(&p, 1);
2678 return result;
2679 }
2680
2681 /** \test Check the signature working to alert when header modifier is
2682 * passed to pcre
2683 */
2684 static int DetectPcreTestSig13(void) {
2685 int result = 0;
2686 Flow f;
2687 uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n"
2688 "Cookie: dummy\r\n\r\n";
2689 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2690 TcpSession ssn;
2691 Packet *p = NULL;
2692 Signature *s = NULL;
2693 ThreadVars th_v;
2694 DetectEngineThreadCtx *det_ctx = NULL;
2695 HtpState *http_state = NULL;
2696
2697 memset(&th_v, 0, sizeof(th_v));
2698 memset(&p, 0, sizeof(p));
2699 memset(&f, 0, sizeof(f));
2700 memset(&ssn, 0, sizeof(ssn));
2701
2702 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
2703
2704 FLOW_INITIALIZE(&f);
2705 f.protoctx = (void *)&ssn;
2706 f.src.family = AF_INET;
2707 f.dst.family = AF_INET;
2708
2709 p->flow = &f;
2710 p->flowflags |= FLOW_PKT_TOSERVER;
2711 p->flowflags |= FLOW_PKT_ESTABLISHED;
2712 f.alproto = ALPROTO_HTTP;
2713
2714 StreamTcpInitConfig(TRUE);
2715 FlowL7DataPtrInit(&f);
2716
2717 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2718 if (de_ctx == NULL) {
2719 goto end;
2720 }
2721
2722 de_ctx->flags |= DE_QUIET;
2723
2724 s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:"
2725 "\"HTTP header\"; pcre:\"/User[-_]Agent[:]?\\sMozilla/H\"; "
2726 " sid:1;)");
2727 if (s == NULL) {
2728 printf("sig parse failed: ");
2729 goto end;
2730 }
2731
2732 SigGroupBuild(de_ctx);
2733 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2734
2735 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
2736 if (r != 0) {
2737 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2738 goto end;
2739 }
2740
2741 http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
2742 if (http_state == NULL) {
2743 printf("no http state: ");
2744 goto end;
2745 }
2746
2747 /* do detect */
2748 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2749
2750 if (!PacketAlertCheck(p, 1)) {
2751 printf("sig 1 failed to match: ");
2752 goto end;
2753 }
2754
2755 result = 1;
2756 end:
2757 if (det_ctx != NULL) {
2758 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2759 }
2760 if (de_ctx != NULL) {
2761 SigGroupCleanup(de_ctx);
2762 DetectEngineCtxFree(de_ctx);
2763 }
2764
2765 FlowL7DataPtrFree(&f);
2766 StreamTcpFreeConfig(TRUE);
2767 UTHFreePackets(&p, 1);
2768 return result;
2769 }
2770
2771 /** \test Check the signature working to alert when header modifier is
2772 * passed to a negated pcre
2773 */
2774 static int DetectPcreTestSig14(void) {
2775 int result = 0;
2776 Flow f;
2777 uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nUser-Agent: IEXPLORER/1.0\r\n"
2778 "Cookie: dummoOOooooO\r\n\r\n";
2779 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2780 TcpSession ssn;
2781 Packet *p = NULL;
2782 Signature *s = NULL;
2783 ThreadVars th_v;
2784 DetectEngineThreadCtx *det_ctx = NULL;
2785 HtpState *http_state = NULL;
2786
2787 memset(&th_v, 0, sizeof(th_v));
2788 memset(&p, 0, sizeof(p));
2789 memset(&f, 0, sizeof(f));
2790 memset(&ssn, 0, sizeof(ssn));
2791
2792 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
2793
2794 FLOW_INITIALIZE(&f);
2795 f.protoctx = (void *)&ssn;
2796 f.src.family = AF_INET;
2797 f.dst.family = AF_INET;
2798
2799 p->flow = &f;
2800 p->flowflags |= FLOW_PKT_TOSERVER;
2801 p->flowflags |= FLOW_PKT_ESTABLISHED;
2802 f.alproto = ALPROTO_HTTP;
2803
2804 StreamTcpInitConfig(TRUE);
2805 FlowL7DataPtrInit(&f);
2806
2807 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2808 if (de_ctx == NULL) {
2809 goto end;
2810 }
2811
2812 de_ctx->flags |= DE_QUIET;
2813
2814 s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:"
2815 "\"HTTP header\"; pcre:!\"/User-Agent[:]?\\s+Mozilla/H\"; "
2816 " sid:1;)");
2817 if (s == NULL) {
2818 printf("sig parse failed: ");
2819 goto end;
2820 }
2821
2822 SigGroupBuild(de_ctx);
2823 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2824
2825 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
2826 if (r != 0) {
2827 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2828 goto end;
2829 }
2830
2831 http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
2832 if (http_state == NULL) {
2833 printf("no http state: ");
2834 goto end;
2835 }
2836
2837 /* do detect */
2838 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2839
2840 if (!PacketAlertCheck(p, 1)) {
2841 printf("sig 1 should match: ");
2842 goto end;
2843 }
2844
2845 result = 1;
2846 end:
2847 if (det_ctx != NULL) {
2848 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2849 }
2850 if (de_ctx != NULL) {
2851 SigGroupCleanup(de_ctx);
2852 DetectEngineCtxFree(de_ctx);
2853 }
2854
2855 FlowL7DataPtrFree(&f);
2856 StreamTcpFreeConfig(TRUE);
2857 UTHFreePackets(&p, 1);
2858 return result;
2859 }
2860
2861 /** \test Test tracking of body chunks per transactions (on requests)
2862 */
2863 static int DetectPcreTxBodyChunksTest01(void) {
2864 int result = 0;
2865 Flow f;
2866 TcpSession ssn;
2867 Packet *p = NULL;
2868 uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n";
2869 uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
2870 uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
2871 uint8_t httpbuf4[] = "Body one!!";
2872 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2873 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
2874 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
2875 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
2876 uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
2877 uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
2878 uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
2879 uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
2880 uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
2881 uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
2882
2883 memset(&f, 0, sizeof(f));
2884 memset(&ssn, 0, sizeof(ssn));
2885
2886 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
2887
2888 FLOW_INITIALIZE(&f);
2889 f.protoctx = (void *)&ssn;
2890 f.proto = IPPROTO_TCP;
2891 f.src.family = AF_INET;
2892 f.dst.family = AF_INET;
2893
2894 p->flow = &f;
2895 p->flowflags |= FLOW_PKT_TOSERVER;
2896 p->flowflags |= FLOW_PKT_ESTABLISHED;
2897 f.alproto = ALPROTO_HTTP;
2898
2899 StreamTcpInitConfig(TRUE);
2900 FlowL7DataPtrInit(&f);
2901
2902 AppLayerHtpEnableRequestBodyCallback();
2903
2904 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1);
2905 if (r != 0) {
2906 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2907 goto end;
2908 }
2909
2910 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
2911 if (r != 0) {
2912 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
2913 goto end;
2914 }
2915
2916 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3);
2917 if (r != 0) {
2918 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
2919 goto end;
2920 }
2921
2922 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4);
2923 if (r != 0) {
2924 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
2925 result = 0;
2926 goto end;
2927 }
2928
2929 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5);
2930 if (r != 0) {
2931 printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
2932 goto end;
2933 }
2934
2935 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6);
2936 if (r != 0) {
2937 printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
2938 goto end;
2939 }
2940
2941 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7);
2942 if (r != 0) {
2943 printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r);
2944 goto end;
2945 }
2946
2947 /* Now we should have 2 transactions, each with it's own list
2948 * of request body chunks (let's test it) */
2949
2950 HtpState *htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
2951 if (htp_state == NULL) {
2952 printf("no http state: ");
2953 result = 0;
2954 goto end;
2955 }
2956
2957 /* hardcoded check of the transactions and it's client body chunks */
2958 if (list_size(htp_state->connp->conn->transactions) != 2) {
2959 printf("The http app layer doesn't have 2 transactions, but it should: ");
2960 goto end;
2961 }
2962
2963 htp_tx_t *t1 = list_get(htp_state->connp->conn->transactions, 0);
2964 htp_tx_t *t2 = list_get(htp_state->connp->conn->transactions, 1);
2965
2966 SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(t1);
2967 if (htud == NULL) {
2968 printf("No body data in t1 (it should be removed only when the tx is destroyed): ");
2969 goto end;
2970 }
2971
2972 HtpBodyChunk *cur = htud->body.first;
2973 if (htud->body.nchunks == 0) {
2974 SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
2975 goto end;
2976 }
2977
2978 if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) {
2979 SCLogDebug("Body data in t1 is not correctly set: ");
2980 goto end;
2981 }
2982
2983 htud = (SCHtpTxUserData *) htp_tx_get_user_data(t2);
2984
2985 cur = htud->body.first;
2986 if (htud->body.nchunks == 0) {
2987 SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
2988 goto end;
2989 }
2990
2991 if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) {
2992 SCLogDebug("Body data in t1 is not correctly set: ");
2993 goto end;
2994 }
2995
2996 FlowL7DataPtrFree(&f);
2997
2998 result = 1;
2999 end:
3000
3001 StreamTcpFreeConfig(TRUE);
3002 FLOW_DESTROY(&f);
3003 UTHFreePacket(p);
3004 return result;
3005 }
3006
3007 /** \test test pcre P modifier with multiple pipelined http transactions */
3008 static int DetectPcreTxBodyChunksTest02(void) {
3009 int result = 0;
3010 Signature *s = NULL;
3011 DetectEngineThreadCtx *det_ctx = NULL;
3012 ThreadVars th_v;
3013 Flow f;
3014 TcpSession ssn;
3015 Packet *p = NULL;
3016 uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
3017 uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
3018 uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
3019 uint8_t httpbuf4[] = "Body one!!";
3020 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3021 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3022 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
3023 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
3024 uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
3025 uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
3026 uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
3027 uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
3028 uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
3029 uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
3030
3031 memset(&th_v, 0, sizeof(th_v));
3032 memset(&f, 0, sizeof(f));
3033 memset(&ssn, 0, sizeof(ssn));
3034
3035 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3036
3037 FLOW_INITIALIZE(&f);
3038 f.protoctx = (void *)&ssn;
3039 f.proto = IPPROTO_TCP;
3040 f.src.family = AF_INET;
3041 f.dst.family = AF_INET;
3042
3043 p->flow = &f;
3044 p->flowflags |= FLOW_PKT_TOSERVER;
3045 p->flowflags |= FLOW_PKT_ESTABLISHED;
3046 f.alproto = ALPROTO_HTTP;
3047
3048 StreamTcpInitConfig(TRUE);
3049 FlowL7DataPtrInit(&f);
3050
3051 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3052 if (de_ctx == NULL) {
3053 goto end;
3054 }
3055
3056 de_ctx->flags |= DE_QUIET;
3057
3058 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)");
3059 if (s == NULL) {
3060 printf("sig parse failed: ");
3061 goto end;
3062 }
3063 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)");
3064 if (s == NULL) {
3065 printf("sig2 parse failed: ");
3066 goto end;
3067 }
3068
3069 SigGroupBuild(de_ctx);
3070 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3071
3072 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
3073 if (r != 0) {
3074 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
3075 goto end;
3076 }
3077
3078 /* do detect */
3079 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3080 if (PacketAlertCheck(p, 1)) {
3081 printf("sig 1 alerted: ");
3082 goto end;
3083 }
3084 p->alerts.cnt = 0;
3085
3086 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
3087 if (r != 0) {
3088 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
3089 goto end;
3090 }
3091
3092 /* do detect */
3093 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3094 if (PacketAlertCheck(p, 1)) {
3095 printf("sig 1 alerted (2): ");
3096 goto end;
3097 }
3098 p->alerts.cnt = 0;
3099
3100 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3);
3101 if (r != 0) {
3102 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
3103 goto end;
3104 }
3105
3106 /* do detect */
3107 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3108 if (PacketAlertCheck(p, 1)) {
3109 printf("signature matched, but shouldn't have: ");
3110 goto end;
3111 }
3112 p->alerts.cnt = 0;
3113
3114 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4);
3115 if (r != 0) {
3116 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
3117 result = 0;
3118 goto end;
3119 }
3120
3121 /* do detect */
3122 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3123 if (!(PacketAlertCheck(p, 1))) {
3124 printf("sig 1 didn't alert: ");
3125 goto end;
3126 }
3127 p->alerts.cnt = 0;
3128
3129 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5);
3130 if (r != 0) {
3131 printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
3132 goto end;
3133 }
3134
3135 /* do detect */
3136 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3137 if (PacketAlertCheck(p, 1)) {
3138 printf("sig 1 alerted (5): ");
3139 goto end;
3140 }
3141 p->alerts.cnt = 0;
3142
3143 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6);
3144 if (r != 0) {
3145 printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
3146 goto end;
3147 }
3148
3149 /* do detect */
3150 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3151 if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) {
3152 printf("sig 1 alerted (request 2, chunk 6): ");
3153 goto end;
3154 }
3155 p->alerts.cnt = 0;
3156
3157 SCLogDebug("sending data chunk 7");
3158
3159 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7);
3160 if (r != 0) {
3161 printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r);
3162 goto end;
3163 }
3164
3165 /* do detect */
3166 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3167 if (!(PacketAlertCheck(p, 2))) {
3168 printf("signature 2 didn't match, but should have: ");
3169 goto end;
3170 }
3171 p->alerts.cnt = 0;
3172
3173 HtpState *htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
3174 if (htp_state == NULL) {
3175 printf("no http state: ");
3176 result = 0;
3177 goto end;
3178 }
3179
3180 /* hardcoded check of the transactions and it's client body chunks */
3181 if (list_size(htp_state->connp->conn->transactions) != 2) {
3182 printf("The http app layer doesn't have 2 transactions, but it should: ");
3183 goto end;
3184 }
3185
3186 htp_tx_t *t1 = list_get(htp_state->connp->conn->transactions, 0);
3187 htp_tx_t *t2 = list_get(htp_state->connp->conn->transactions, 1);
3188
3189 SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(t1);
3190
3191 HtpBodyChunk *cur = htud->body.first;
3192 if (htud->body.nchunks == 0) {
3193 SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
3194 goto end;
3195 }
3196
3197 if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) {
3198 SCLogDebug("Body data in t1 is not correctly set: ");
3199 goto end;
3200 }
3201
3202 htud = (SCHtpTxUserData *) htp_tx_get_user_data(t2);
3203
3204 cur = htud->body.first;
3205 if (htud->body.nchunks == 0) {
3206 SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
3207 goto end;
3208 }
3209
3210 if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) {
3211 SCLogDebug("Body data in t1 is not correctly set: ");
3212 goto end;
3213 }
3214
3215 result = 1;
3216 end:
3217 if (det_ctx != NULL) {
3218 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3219 }
3220 if (de_ctx != NULL) {
3221 SigGroupCleanup(de_ctx);
3222 DetectEngineCtxFree(de_ctx);
3223 }
3224
3225 FlowL7DataPtrFree(&f);
3226 StreamTcpFreeConfig(TRUE);
3227 FLOW_DESTROY(&f);
3228 UTHFreePacket(p);
3229 return result;
3230 }
3231
3232 /** \test multiple http transactions and body chunks of request handling */
3233 static int DetectPcreTxBodyChunksTest03(void) {
3234 int result = 0;
3235 Signature *s = NULL;
3236 DetectEngineThreadCtx *det_ctx = NULL;
3237 ThreadVars th_v;
3238 Flow f;
3239 TcpSession ssn;
3240 Packet *p = NULL;
3241 uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
3242 uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
3243 uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
3244 uint8_t httpbuf4[] = "Body one!!";
3245 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3246 uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3247 uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
3248 uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
3249 uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
3250 uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
3251 uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
3252 uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
3253 uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
3254 uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
3255
3256 memset(&th_v, 0, sizeof(th_v));
3257 memset(&f, 0, sizeof(f));
3258 memset(&ssn, 0, sizeof(ssn));
3259
3260 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3261
3262 FLOW_INITIALIZE(&f);
3263 f.protoctx = (void *)&ssn;
3264 f.proto = IPPROTO_TCP;
3265 f.src.family = AF_INET;
3266 f.dst.family = AF_INET;
3267
3268 p->flow = &f;
3269 p->flowflags |= FLOW_PKT_TOSERVER;
3270 p->flowflags |= FLOW_PKT_ESTABLISHED;
3271 f.alproto = ALPROTO_HTTP;
3272
3273 StreamTcpInitConfig(TRUE);
3274 FlowL7DataPtrInit(&f);
3275
3276 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3277 if (de_ctx == NULL) {
3278 goto end;
3279 }
3280
3281 de_ctx->flags |= DE_QUIET;
3282
3283 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)");
3284 if (s == NULL) {
3285 printf("sig parse failed: ");
3286 goto end;
3287 }
3288 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)");
3289 if (s == NULL) {
3290 printf("sig2 parse failed: ");
3291 goto end;
3292 }
3293
3294 SigGroupBuild(de_ctx);
3295 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3296
3297 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
3298 if (r != 0) {
3299 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
3300 goto end;
3301 }
3302
3303 /* do detect */
3304 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3305 if (PacketAlertCheck(p, 1)) {
3306 printf("sig 1 alerted: ");
3307 goto end;
3308 }
3309 p->alerts.cnt = 0;
3310
3311 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
3312 if (r != 0) {
3313 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
3314 goto end;
3315 }
3316
3317 /* do detect */
3318 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3319 if (PacketAlertCheck(p, 1)) {
3320 printf("sig 1 alerted (2): ");
3321 goto end;
3322 }
3323 p->alerts.cnt = 0;
3324
3325 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3);
3326 if (r != 0) {
3327 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
3328 goto end;
3329 }
3330
3331 /* do detect */
3332 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3333 if (PacketAlertCheck(p, 1)) {
3334 printf("signature matched, but shouldn't have: ");
3335 goto end;
3336 }
3337 p->alerts.cnt = 0;
3338
3339 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4);
3340 if (r != 0) {
3341 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
3342 result = 0;
3343 goto end;
3344 }
3345
3346 /* do detect */
3347 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3348 if (!(PacketAlertCheck(p, 1))) {
3349 printf("sig 1 didn't alert: ");
3350 goto end;
3351 }
3352 p->alerts.cnt = 0;
3353
3354 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5);
3355 if (r != 0) {
3356 printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
3357 goto end;
3358 }
3359
3360 /* do detect */
3361 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3362 if (PacketAlertCheck(p, 1)) {
3363 printf("sig 1 alerted (5): ");
3364 goto end;
3365 }
3366 p->alerts.cnt = 0;
3367
3368 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6);
3369 if (r != 0) {
3370 printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
3371 goto end;
3372 }
3373
3374 /* do detect */
3375 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3376 if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) {
3377 printf("sig 1 alerted (request 2, chunk 6): ");
3378 goto end;
3379 }
3380 p->alerts.cnt = 0;
3381
3382 SCLogDebug("sending data chunk 7");
3383
3384 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7);
3385 if (r != 0) {
3386 printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r);
3387 goto end;
3388 }
3389
3390 /* do detect */
3391 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3392 if (!(PacketAlertCheck(p, 2))) {
3393 printf("signature 2 didn't match, but should have: ");
3394 goto end;
3395 }
3396 p->alerts.cnt = 0;
3397
3398 HtpState *htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
3399 if (htp_state == NULL) {
3400 printf("no http state: ");
3401 result = 0;
3402 goto end;
3403 }
3404
3405 if (list_size(htp_state->connp->conn->transactions) != 2) {
3406 printf("The http app layer doesn't have 2 transactions, but it should: ");
3407 goto end;
3408 }
3409
3410 result = 1;
3411 end:
3412 if (det_ctx != NULL) {
3413 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3414 }
3415 if (de_ctx != NULL) {
3416 SigGroupCleanup(de_ctx);
3417 DetectEngineCtxFree(de_ctx);
3418 }
3419
3420 FlowL7DataPtrFree(&f);
3421 StreamTcpFreeConfig(TRUE);
3422 FLOW_DESTROY(&f);
3423 UTHFreePacket(p);
18333424 return result;
18343425 }
18353426
18653456 UtRegisterTest("DetectPcreTestSig06", DetectPcreTestSig06, 1);
18663457 UtRegisterTest("DetectPcreTestSig07 -- anchored pcre", DetectPcreTestSig07, 1);
18673458 UtRegisterTest("DetectPcreTestSig08 -- anchored pcre", DetectPcreTestSig08, 1);
3459 UtRegisterTest("DetectPcreTestSig09 -- Cookie modifier", DetectPcreTestSig09, 1);
3460 UtRegisterTest("DetectPcreTestSig10 -- negated Cookie modifier", DetectPcreTestSig10, 1);
3461 UtRegisterTest("DetectPcreTestSig11 -- Method modifier", DetectPcreTestSig11, 1);
3462 UtRegisterTest("DetectPcreTestSig12 -- negated Method modifier", DetectPcreTestSig12, 1);
3463 UtRegisterTest("DetectPcreTestSig13 -- Header modifier", DetectPcreTestSig13, 1);
3464 UtRegisterTest("DetectPcreTestSig14 -- negated Header modifier", DetectPcreTestSig14, 1);
3465 UtRegisterTest("DetectPcreTxBodyChunksTest01", DetectPcreTxBodyChunksTest01, 1);
3466 UtRegisterTest("DetectPcreTxBodyChunksTest02 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest02, 1);
3467 UtRegisterTest("DetectPcreTxBodyChunksTest03 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest03, 1);
18683468 #endif /* UNITTESTS */
18693469 }
18703470
2323 #ifndef __DETECT_PCRE_H__
2424 #define __DETECT_PCRE_H__
2525
26 #define DETECT_PCRE_RELATIVE 0x01
27 #define DETECT_PCRE_RAWBYTES 0x02
28 #define DETECT_PCRE_URI 0x04
26 #define DETECT_PCRE_RELATIVE 0x0001
27 #define DETECT_PCRE_RAWBYTES 0x0002
28 #define DETECT_PCRE_URI 0x0004
2929
30 #define DETECT_PCRE_CAPTURE_PKT 0x08
31 #define DETECT_PCRE_CAPTURE_FLOW 0x10
32 #define DETECT_PCRE_MATCH_LIMIT 0x20
30 #define DETECT_PCRE_CAPTURE_PKT 0x0008
31 #define DETECT_PCRE_CAPTURE_FLOW 0x0010
32 #define DETECT_PCRE_MATCH_LIMIT 0x0020
3333
34 #define DETECT_PCRE_HTTP_BODY_AL 0x40
35 #define DETECT_PCRE_RELATIVE_NEXT 0x80
34 #define DETECT_PCRE_HTTP_BODY_AL 0x0040
35 #define DETECT_PCRE_RELATIVE_NEXT 0x0080
36
37 /* new modifiers 2.8.5.3 support */
38 #define DETECT_PCRE_HEADER 0x0100
39 #define DETECT_PCRE_COOKIE 0x0200
40 #define DETECT_PCRE_METHOD 0x0400
3641
3742 typedef struct DetectPcreData_ {
3843 /* pcre options */
4045 pcre_extra *sd;
4146 int opts;
4247
43 uint8_t flags;
48 uint16_t flags;
4449 uint8_t negate;
4550
4651 char *capname;
0 /* Copyright (C) 2007-2010 Open Information Security Foundation
1 *
2 * You can copy, redistribute or modify this Program under the terms of
3 * the GNU General Public License version 2 as published by the Free
4 * Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * version 2 along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
14 * 02110-1301, USA.
15 */
16
17 /**
18 * \file
19 *
20 * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
21 *
22 * Implements the ssh.protoversion keyword
23 * You can specify a concrete version like ssh.protoversion: 1.66
24 * or search for protoversion 2 compat (1.99 is considered as 2) like
25 * ssh.protoversion:2_compat
26 * or just the beginning of the string like ssh.protoversion:"1."
27 */
28
29 #include "suricata-common.h"
30 #include "threads.h"
31 #include "debug.h"
32 #include "decode.h"
33
34 #include "detect.h"
35 #include "detect-parse.h"
36
37 #include "detect-engine.h"
38 #include "detect-engine-mpm.h"
39 #include "detect-engine-state.h"
40
41 #include "flow.h"
42 #include "flow-var.h"
43 #include "flow-util.h"
44
45 #include "util-debug.h"
46 #include "util-unittest.h"
47 #include "util-unittest-helper.h"
48
49 #include "app-layer.h"
50
51 #include "app-layer-ssh.h"
52 #include "detect-ssh-proto-version.h"
53
54 #include "stream-tcp.h"
55
56 /**
57 * \brief Regex for parsing the protoversion string
58 */
59 #define PARSE_REGEX "^\\s*\"?\\s*([0-9]+([\\.\\-0-9]+)?|2_compat)\\s*\"?\\s*$"
60
61 static pcre *parse_regex;
62 static pcre_extra *parse_regex_study;
63
64 int DetectSshVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *);
65 static int DetectSshVersionSetup (DetectEngineCtx *, Signature *, char *);
66 void DetectSshVersionRegisterTests(void);
67 void DetectSshVersionFree(void *);
68
69 /**
70 * \brief Registration function for keyword: ssh.protoversion
71 */
72 void DetectSshVersionRegister(void) {
73 sigmatch_table[DETECT_AL_SSH_PROTOVERSION].name = "ssh.protoversion";
74 sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Match = NULL;
75 sigmatch_table[DETECT_AL_SSH_PROTOVERSION].AppLayerMatch = DetectSshVersionMatch;
76 sigmatch_table[DETECT_AL_SSH_PROTOVERSION].alproto = ALPROTO_SSH;
77 sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Setup = DetectSshVersionSetup;
78 sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Free = DetectSshVersionFree;
79 sigmatch_table[DETECT_AL_SSH_PROTOVERSION].RegisterTests = DetectSshVersionRegisterTests;
80
81 const char *eb;
82 int eo;
83 int opts = 0;
84
85 SCLogDebug("registering ssh.protoversion rule option");
86
87 parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL);
88 if (parse_regex == NULL) {
89 SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s",
90 PARSE_REGEX, eo, eb);
91 goto error;
92 }
93
94 parse_regex_study = pcre_study(parse_regex, 0, &eb);
95 if (eb != NULL) {
96 SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb);
97 goto error;
98 }
99 return;
100
101 error:
102 return;
103 }
104
105 /**
106 * \brief match the specified version on a ssh session
107 *
108 * \param t pointer to thread vars
109 * \param det_ctx pointer to the pattern matcher thread
110 * \param p pointer to the current packet
111 * \param m pointer to the sigmatch that we will cast into DetectSshVersionData
112 *
113 * \retval 0 no match
114 * \retval 1 match
115 */
116 int DetectSshVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m)
117 {
118 SCEnter();
119
120 DetectSshVersionData *ssh = (DetectSshVersionData *)m->ctx;
121 SshState *ssh_state = (SshState *)state;
122 if (ssh_state == NULL) {
123 SCLogDebug("no ssh state, no match");
124 SCReturnInt(0);
125 }
126
127 int ret = 0;
128 SCMutexLock(&f->m);
129 if (flags & STREAM_TOCLIENT && ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED) {
130 if (ssh->flags & SSH_FLAG_PROTOVERSION_2_COMPAT) {
131 SCLogDebug("looking for ssh server protoversion 2 compat");
132 if (strncmp((char *) ssh_state->server_proto_version, "2", 1) == 0 ||
133 strncmp((char *) ssh_state->server_proto_version, "2.", 2) == 0 ||
134 strncmp((char *) ssh_state->server_proto_version, "1.99", 4) == 0)
135 ret = 1;
136 } else {
137 SCLogDebug("looking for ssh server protoversion %s length %"PRIu16"", ssh->ver, ssh->len);
138 ret = (strncmp((char *) ssh_state->server_proto_version, (char *) ssh->ver, ssh->len) == 0)? 1 : 0;
139 }
140 } else if (flags & STREAM_TOSERVER && ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED) {
141 if (ssh->flags & SSH_FLAG_PROTOVERSION_2_COMPAT) {
142 SCLogDebug("looking for client ssh client protoversion 2 compat");
143 if (strncmp((char *) ssh_state->client_proto_version, "2", 1) == 0 ||
144 strncmp((char *) ssh_state->client_proto_version, "2.", 2) == 0 ||
145 strncmp((char *) ssh_state->client_proto_version, "1.99", 4) == 0)
146 ret = 1;
147 } else {
148 SCLogDebug("looking for ssh client protoversion %s length %"PRIu16"", ssh->ver, ssh->len);
149 ret = (strncmp((char *) ssh_state->client_proto_version, (char *) ssh->ver, ssh->len) == 0)? 1 : 0;
150 }
151 }
152 SCMutexUnlock(&f->m);
153 SCReturnInt(ret);
154 }
155
156 /**
157 * \brief This function is used to parse IPV4 ip_id passed via keyword: "id"
158 *
159 * \param idstr Pointer to the user provided id option
160 *
161 * \retval id_d pointer to DetectSshVersionData on success
162 * \retval NULL on failure
163 */
164 DetectSshVersionData *DetectSshVersionParse (char *str)
165 {
166 DetectSshVersionData *ssh = NULL;
167 #define MAX_SUBSTRINGS 30
168 int ret = 0, res = 0;
169 int ov[MAX_SUBSTRINGS];
170
171 ret = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0,
172 ov, MAX_SUBSTRINGS);
173
174 if (ret < 1 || ret > 3) {
175 SCLogError(SC_ERR_PCRE_MATCH, "invalid ssh.protoversion option");
176 goto error;
177 }
178
179 if (ret > 1) {
180 const char *str_ptr;
181 res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr);
182 if (res < 0) {
183 SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
184 goto error;
185 }
186
187 /* We have a correct id option */
188 ssh = SCMalloc(sizeof(DetectSshVersionData));
189 if (ssh == NULL)
190 goto error;
191
192 memset(ssh, 0x00, sizeof(DetectSshVersionData));
193
194 /* If we expect a protocol version 2 or 1.99 (considered 2, we
195 * will compare it with both strings) */
196 if (strcmp("2_compat", str_ptr) == 0) {
197 ssh->flags |= SSH_FLAG_PROTOVERSION_2_COMPAT;
198 SCLogDebug("will look for ssh protocol version 2 (2, 2.0, 1.99 that's considered as 2");
199 return ssh;
200 }
201
202 ssh->ver = (uint8_t *)SCStrdup((char*)str_ptr);
203 if (ssh->ver == NULL) {
204 goto error;
205 }
206 ssh->len = strlen((char *) ssh->ver);
207
208 SCLogDebug("will look for ssh %s", ssh->ver);
209 }
210
211 return ssh;
212
213 error:
214 if (ssh != NULL)
215 DetectSshVersionFree(ssh);
216 return NULL;
217
218 }
219
220 /**
221 * \brief this function is used to add the parsed "id" option
222 * \brief into the current signature
223 *
224 * \param de_ctx pointer to the Detection Engine Context
225 * \param s pointer to the Current Signature
226 * \param idstr pointer to the user provided "id" option
227 *
228 * \retval 0 on Success
229 * \retval -1 on Failure
230 */
231 static int DetectSshVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *str)
232 {
233 DetectSshVersionData *ssh = NULL;
234 SigMatch *sm = NULL;
235
236 ssh = DetectSshVersionParse(str);
237 if (ssh == NULL)
238 goto error;
239
240 /* Okay so far so good, lets get this into a SigMatch
241 * and put it in the Signature. */
242 sm = SigMatchAlloc();
243 if (sm == NULL)
244 goto error;
245
246 sm->type = DETECT_AL_SSH_PROTOVERSION;
247 sm->ctx = (void *)ssh;
248
249 SigMatchAppendAppLayer(s, sm);
250
251 if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_SSH) {
252 SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords.");
253 goto error;
254 }
255
256 s->alproto = ALPROTO_SSH;
257 return 0;
258
259 error:
260 if (ssh != NULL)
261 DetectSshVersionFree(ssh);
262 if (sm != NULL)
263 SCFree(sm);
264 return -1;
265
266 }
267
268 /**
269 * \brief this function will free memory associated with DetectSshVersionData
270 *
271 * \param id_d pointer to DetectSshVersionData
272 */
273 void DetectSshVersionFree(void *ptr) {
274 DetectSshVersionData *id_d = (DetectSshVersionData *)ptr;
275 SCFree(id_d);
276 }
277
278 #ifdef UNITTESTS /* UNITTESTS */
279
280 /**
281 * \test DetectSshVersionTestParse01 is a test to make sure that we parse
282 * a proto version correctly
283 */
284 int DetectSshVersionTestParse01 (void) {
285 DetectSshVersionData *ssh = NULL;
286 ssh = DetectSshVersionParse("1.0");
287 if (ssh != NULL && strncmp((char *) ssh->ver, "1.0", 3) == 0) {
288 DetectSshVersionFree(ssh);
289 return 1;
290 }
291
292 return 0;
293 }
294
295 /**
296 * \test DetectSshVersionTestParse02 is a test to make sure that we parse
297 * the proto version (compatible with proto version 2) correctly
298 */
299 int DetectSshVersionTestParse02 (void) {
300 DetectSshVersionData *ssh = NULL;
301 ssh = DetectSshVersionParse("2_compat");
302 if (ssh->flags & SSH_FLAG_PROTOVERSION_2_COMPAT) {
303 DetectSshVersionFree(ssh);
304 return 1;
305 }
306
307 return 0;
308 }
309
310 /**
311 * \test DetectSshVersionTestParse03 is a test to make sure that we
312 * don't return a ssh_data with an invalid value specified
313 */
314 int DetectSshVersionTestParse03 (void) {
315 DetectSshVersionData *ssh = NULL;
316 ssh = DetectSshVersionParse("2_com");
317 if (ssh != NULL) {
318 DetectSshVersionFree(ssh);
319 return 0;
320 }
321 ssh = DetectSshVersionParse("");
322 if (ssh != NULL) {
323 DetectSshVersionFree(ssh);
324 return 0;
325 }
326 ssh = DetectSshVersionParse(".1");
327 if (ssh != NULL) {
328 DetectSshVersionFree(ssh);
329 return 0;
330 }
331 ssh = DetectSshVersionParse("lalala");
332 if (ssh != NULL) {
333 DetectSshVersionFree(ssh);
334 return 0;
335 }
336
337 return 1;
338 }
339
340
341 #include "stream-tcp-reassemble.h"
342
343 /** \test Send a get request in three chunks + more data. */
344 static int DetectSshVersionTestDetect01(void) {
345 int result = 0;
346 Flow f;
347 uint8_t sshbuf1[] = "SSH-1.";
348 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
349 uint8_t sshbuf2[] = "10-PuTTY_2.123" ;
350 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
351 uint8_t sshbuf3[] = "\n";
352 uint32_t sshlen3 = sizeof(sshbuf3) - 1;
353 uint8_t sshbuf4[] = "whatever...";
354 uint32_t sshlen4 = sizeof(sshbuf4) - 1;
355 TcpSession ssn;
356 Packet *p = NULL;
357 Signature *s = NULL;
358 ThreadVars th_v;
359 DetectEngineThreadCtx *det_ctx = NULL;
360
361 memset(&th_v, 0, sizeof(th_v));
362 memset(&f, 0, sizeof(f));
363 memset(&ssn, 0, sizeof(ssn));
364
365 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
366
367 FLOW_INITIALIZE(&f);
368 f.protoctx = (void *)&ssn;
369 p->flow = &f;
370 p->flowflags |= FLOW_PKT_TOSERVER;
371 p->flowflags |= FLOW_PKT_ESTABLISHED;
372 f.alproto = ALPROTO_SSH;
373
374 StreamTcpInitConfig(TRUE);
375 FlowL7DataPtrInit(&f);
376
377 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
378 if (de_ctx == NULL) {
379 goto end;
380 }
381
382 de_ctx->flags |= DE_QUIET;
383
384 s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:1.10; sid:1;)");
385 if (s == NULL) {
386 goto end;
387 }
388
389 SigGroupBuild(de_ctx);
390 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
391
392 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
393 if (r != 0) {
394 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
395 goto end;
396 }
397
398 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
399 if (r != 0) {
400 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
401 goto end;
402 }
403
404 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
405 if (r != 0) {
406 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
407 goto end;
408 }
409
410 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4);
411 if (r != 0) {
412 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
413 goto end;
414 }
415
416 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
417 if (ssh_state == NULL) {
418 printf("no ssh state: ");
419 goto end;
420 }
421
422 /* do detect */
423 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
424
425 if ( !(PacketAlertCheck(p, 1))) {
426 printf("Error, the sig should match: ");
427 goto end;
428 }
429
430 result = 1;
431 end:
432 SigGroupCleanup(de_ctx);
433 SigCleanSignatures(de_ctx);
434
435 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
436 DetectEngineCtxFree(de_ctx);
437
438 FlowL7DataPtrFree(&f);
439 StreamTcpFreeConfig(TRUE);
440 FLOW_DESTROY(&f);
441
442 UTHFreePackets(&p, 1);
443 return result;
444 }
445
446 /** \test Send a get request in three chunks + more data. */
447 static int DetectSshVersionTestDetect02(void) {
448 int result = 0;
449 Flow f;
450 uint8_t sshbuf1[] = "SSH-1.";
451 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
452 uint8_t sshbuf2[] = "99-PuTTY_2.123" ;
453 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
454 uint8_t sshbuf3[] = "\n";
455 uint32_t sshlen3 = sizeof(sshbuf3) - 1;
456 uint8_t sshbuf4[] = "whatever...";
457 uint32_t sshlen4 = sizeof(sshbuf4) - 1;
458 TcpSession ssn;
459 Packet *p = NULL;
460 Signature *s = NULL;
461 ThreadVars th_v;
462 DetectEngineThreadCtx *det_ctx = NULL;
463
464 memset(&th_v, 0, sizeof(th_v));
465 memset(&f, 0, sizeof(f));
466 memset(&ssn, 0, sizeof(ssn));
467
468 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
469
470 FLOW_INITIALIZE(&f);
471 f.protoctx = (void *)&ssn;
472 p->flow = &f;
473 p->flowflags |= FLOW_PKT_TOSERVER;
474 p->flowflags |= FLOW_PKT_ESTABLISHED;
475 f.alproto = ALPROTO_SSH;
476
477 StreamTcpInitConfig(TRUE);
478 FlowL7DataPtrInit(&f);
479
480 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
481 if (de_ctx == NULL) {
482 goto end;
483 }
484
485 de_ctx->flags |= DE_QUIET;
486
487 s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:2_compat; sid:1;)");
488 if (s == NULL) {
489 goto end;
490 }
491
492 SigGroupBuild(de_ctx);
493 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
494
495 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
496 if (r != 0) {
497 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
498 goto end;
499 }
500
501 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
502 if (r != 0) {
503 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
504 goto end;
505 }
506
507 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
508 if (r != 0) {
509 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
510 goto end;
511 }
512
513 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4);
514 if (r != 0) {
515 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
516 goto end;
517 }
518
519 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
520 if (ssh_state == NULL) {
521 printf("no ssh state: ");
522 goto end;
523 }
524
525 /* do detect */
526 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
527
528 if ( !(PacketAlertCheck(p, 1))) {
529 printf("Error, the sig should match: ");
530 goto end;
531 }
532
533 result = 1;
534 end:
535 SigGroupCleanup(de_ctx);
536 SigCleanSignatures(de_ctx);
537
538 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
539 DetectEngineCtxFree(de_ctx);
540
541 FlowL7DataPtrFree(&f);
542 StreamTcpFreeConfig(TRUE);
543 FLOW_DESTROY(&f);
544
545 UTHFreePackets(&p, 1);
546 return result;
547 }
548
549 /** \test Send a get request in three chunks + more data. */
550 static int DetectSshVersionTestDetect03(void) {
551 int result = 0;
552 Flow f;
553 uint8_t sshbuf1[] = "SSH-1.";
554 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
555 uint8_t sshbuf2[] = "7-PuTTY_2.123" ;
556 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
557 uint8_t sshbuf3[] = "\n";
558 uint32_t sshlen3 = sizeof(sshbuf3) - 1;
559 uint8_t sshbuf4[] = "whatever...";
560 uint32_t sshlen4 = sizeof(sshbuf4) - 1;
561 TcpSession ssn;
562 Packet *p = NULL;
563 Signature *s = NULL;
564 ThreadVars th_v;
565 DetectEngineThreadCtx *det_ctx = NULL;
566
567 memset(&th_v, 0, sizeof(th_v));
568 memset(&f, 0, sizeof(f));
569 memset(&ssn, 0, sizeof(ssn));
570
571 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
572
573 FLOW_INITIALIZE(&f);
574 f.protoctx = (void *)&ssn;
575 p->flow = &f;
576 p->flowflags |= FLOW_PKT_TOSERVER;
577 p->flowflags |= FLOW_PKT_ESTABLISHED;
578 f.alproto = ALPROTO_SSH;
579
580 StreamTcpInitConfig(TRUE);
581 FlowL7DataPtrInit(&f);
582
583 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
584 if (de_ctx == NULL) {
585 goto end;
586 }
587
588 de_ctx->flags |= DE_QUIET;
589
590 s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.protoversion:2_compat; sid:1;)");
591 if (s == NULL) {
592 goto end;
593 }
594
595 SigGroupBuild(de_ctx);
596 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
597
598 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
599 if (r != 0) {
600 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
601 goto end;
602 }
603
604 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
605 if (r != 0) {
606 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
607 goto end;
608 }
609
610 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
611 if (r != 0) {
612 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
613 goto end;
614 }
615
616 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4);
617 if (r != 0) {
618 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
619 goto end;
620 }
621
622 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
623 if (ssh_state == NULL) {
624 printf("no ssh state: ");
625 goto end;
626 }
627
628 /* do detect */
629 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
630
631 if (PacketAlertCheck(p, 1)) {
632 printf("Error, 1.7 version is not 2 compat, so the sig should not match: ");
633 goto end;
634 }
635
636 result = 1;
637 end:
638 SigGroupCleanup(de_ctx);
639 SigCleanSignatures(de_ctx);
640
641 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
642 DetectEngineCtxFree(de_ctx);
643
644 FlowL7DataPtrFree(&f);
645 StreamTcpFreeConfig(TRUE);
646 FLOW_DESTROY(&f);
647
648 UTHFreePackets(&p, 1);
649 return result;
650 }
651
652 #endif /* UNITTESTS */
653
654 /**
655 * \brief this function registers unit tests for DetectSshVersion
656 */
657 void DetectSshVersionRegisterTests(void) {
658 #ifdef UNITTESTS /* UNITTESTS */
659 UtRegisterTest("DetectSshVersionTestParse01", DetectSshVersionTestParse01, 1);
660 UtRegisterTest("DetectSshVersionTestParse02", DetectSshVersionTestParse02, 1);
661 UtRegisterTest("DetectSshVersionTestParse03", DetectSshVersionTestParse03, 1);
662 UtRegisterTest("DetectSshVersionTestDetect01", DetectSshVersionTestDetect01, 1);
663 UtRegisterTest("DetectSshVersionTestDetect02", DetectSshVersionTestDetect02, 1);
664 UtRegisterTest("DetectSshVersionTestDetect03", DetectSshVersionTestDetect03, 1);
665 #endif /* UNITTESTS */
666 }
667
0 /* Copyright (C) 2007-2010 Open Information Security Foundation
1 *
2 * You can copy, redistribute or modify this Program under the terms of
3 * the GNU General Public License version 2 as published by the Free
4 * Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * version 2 along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
14 * 02110-1301, USA.
15 */
16
17 /**
18 * \file
19 *
20 * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
21 */
22
23 #ifndef __DETECT_SSH_VERSION_H__
24 #define __DETECT_SSH_VERSION_H__
25
26 /** proto version 1.99 is considered proto version 2 */
27 #define SSH_FLAG_PROTOVERSION_2_COMPAT 0x01
28
29 typedef struct DetectSshVersionData_ {
30 uint8_t *ver; /** ssh version to match */
31 uint16_t len; /** ssh version length to match */
32 uint8_t flags;
33 } DetectSshVersionData;
34
35 /* prototypes */
36 void DetectSshVersionRegister (void);
37
38 #endif /* __DETECT_SSH_VERSION_H__ */
39
0 /* Copyright (C) 2007-2010 Open Information Security Foundation
1 *
2 * You can copy, redistribute or modify this Program under the terms of
3 * the GNU General Public License version 2 as published by the Free
4 * Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * version 2 along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
14 * 02110-1301, USA.
15 */
16
17 /**
18 * \file
19 *
20 * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
21 *
22 * Implements the ssh.softwareversion keyword
23 * You can match over the software version string of ssh, and it will
24 * be compared from the beginning of the string so you can say for
25 * example ssh.softwareversion:"PuTTY" and it can match, or you can
26 * also specify the version, something like
27 * ssh.softwareversion:"PuTTY-Release-0.55"
28 * I find this useful to match over a known vulnerable server/client
29 * software version incombination to other checks, so you can know
30 * that the risk is higher
31 */
32
33 #include "suricata-common.h"
34 #include "threads.h"
35 #include "debug.h"
36 #include "decode.h"
37
38 #include "detect.h"
39 #include "detect-parse.h"
40
41 #include "detect-engine.h"
42 #include "detect-engine-mpm.h"
43 #include "detect-engine-state.h"
44
45 #include "flow.h"
46 #include "flow-var.h"
47 #include "flow-util.h"
48
49 #include "util-debug.h"
50 #include "util-unittest.h"
51 #include "util-unittest-helper.h"
52
53 #include "app-layer.h"
54
55 #include "app-layer-ssh.h"
56 #include "detect-ssh-software-version.h"
57
58 #include "stream-tcp.h"
59
60 /**
61 * \brief Regex for parsing the softwareversion string
62 */
63 #define PARSE_REGEX "^\\s*\"?\\s*?([0-9a-zA-Z\\.\\-\\_]+)\\s*\"?\\s*$"
64
65 static pcre *parse_regex;
66 static pcre_extra *parse_regex_study;
67
68 int DetectSshSoftwareVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *);
69 static int DetectSshSoftwareVersionSetup (DetectEngineCtx *, Signature *, char *);
70 void DetectSshSoftwareVersionRegisterTests(void);
71 void DetectSshSoftwareVersionFree(void *);
72 void DetectSshSoftwareVersionRegister(void);
73
74 /**
75 * \brief Registration function for keyword: ssh.softwareversion
76 */
77 void DetectSshSoftwareVersionRegister(void) {
78 sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].name = "ssh.softwareversion";
79 sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Match = NULL;
80 sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].AppLayerMatch = DetectSshSoftwareVersionMatch;
81 sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].alproto = ALPROTO_SSH;
82 sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Setup = DetectSshSoftwareVersionSetup;
83 sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Free = DetectSshSoftwareVersionFree;
84 sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].RegisterTests = DetectSshSoftwareVersionRegisterTests;
85
86 const char *eb;
87 int eo;
88 int opts = 0;
89
90 SCLogDebug("registering ssh.softwareversion rule option");
91
92 parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL);
93 if (parse_regex == NULL) {
94 SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s",
95 PARSE_REGEX, eo, eb);
96 goto error;
97 }
98
99 parse_regex_study = pcre_study(parse_regex, 0, &eb);
100 if (eb != NULL) {
101 SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb);
102 goto error;
103 }
104 return;
105
106 error:
107 return;
108 }
109
110 /**
111 * \brief match the specified version on a ssh session
112 *
113 * \param t pointer to thread vars
114 * \param det_ctx pointer to the pattern matcher thread
115 * \param p pointer to the current packet
116 * \param m pointer to the sigmatch that we will cast into DetectSshSoftwareVersionData
117 *
118 * \retval 0 no match
119 * \retval 1 match
120 */
121 int DetectSshSoftwareVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m)
122 {
123 SCEnter();
124
125 DetectSshSoftwareVersionData *ssh = (DetectSshSoftwareVersionData *)m->ctx;
126 SshState *ssh_state = (SshState *)state;
127 if (ssh_state == NULL) {
128 SCLogDebug("no ssh state, no match");
129 SCReturnInt(0);
130 }
131
132 int ret = 0;
133 SCMutexLock(&f->m);
134 if (flags & STREAM_TOCLIENT && ssh_state->flags & SSH_FLAG_SERVER_VERSION_PARSED) {
135 SCLogDebug("looking for ssh server softwareversion %s length %"PRIu16" on %s", ssh->software_ver, ssh->len, ssh_state->server_software_version);
136 ret = (strncmp((char *) ssh_state->server_software_version, (char *) ssh->software_ver, ssh->len) == 0)? 1 : 0;
137 } else if (flags & STREAM_TOSERVER && ssh_state->flags & SSH_FLAG_CLIENT_VERSION_PARSED) {
138 SCLogDebug("looking for ssh client softwareversion %s length %"PRIu16" on %s", ssh->software_ver, ssh->len, ssh_state->client_software_version);
139 ret = (strncmp((char *) ssh_state->client_software_version, (char *) ssh->software_ver, ssh->len) == 0)? 1 : 0;
140 }
141 SCMutexUnlock(&f->m);
142 SCReturnInt(ret);
143 }
144
145 /**
146 * \brief This function is used to parse IPV4 ip_id passed via keyword: "id"
147 *
148 * \param idstr Pointer to the user provided id option
149 *
150 * \retval id_d pointer to DetectSshSoftwareVersionData on success
151 * \retval NULL on failure
152 */
153 DetectSshSoftwareVersionData *DetectSshSoftwareVersionParse (char *str)
154 {
155 DetectSshSoftwareVersionData *ssh = NULL;
156 #define MAX_SUBSTRINGS 30
157 int ret = 0, res = 0;
158 int ov[MAX_SUBSTRINGS];
159
160 ret = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0,
161 ov, MAX_SUBSTRINGS);
162
163 if (ret < 1 || ret > 3) {
164 SCLogError(SC_ERR_PCRE_MATCH, "invalid ssh.softwareversion option");
165 goto error;
166 }
167
168 if (ret > 1) {
169 const char *str_ptr;
170 res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 1, &str_ptr);
171 if (res < 0) {
172 SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
173 goto error;
174 }
175
176 /* We have a correct id option */
177 ssh = SCMalloc(sizeof(DetectSshSoftwareVersionData));
178 if (ssh == NULL)
179 goto error;
180
181 ssh->software_ver = (uint8_t *)SCStrdup((char*)str_ptr);
182 if (ssh->software_ver == NULL) {
183 goto error;
184 }
185 ssh->len = strlen((char *) ssh->software_ver);
186
187 SCLogDebug("will look for ssh %s", ssh->software_ver);
188 }
189
190 return ssh;
191
192 error:
193 if (ssh != NULL)
194 DetectSshSoftwareVersionFree(ssh);
195 return NULL;
196
197 }
198
199 /**
200 * \brief this function is used to add the parsed "id" option
201 * \brief into the current signature
202 *
203 * \param de_ctx pointer to the Detection Engine Context
204 * \param s pointer to the Current Signature
205 * \param idstr pointer to the user provided "id" option
206 *
207 * \retval 0 on Success
208 * \retval -1 on Failure
209 */
210 static int DetectSshSoftwareVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *str)
211 {
212 DetectSshSoftwareVersionData *ssh = NULL;
213 SigMatch *sm = NULL;
214
215 ssh = DetectSshSoftwareVersionParse(str);
216 if (ssh == NULL) goto error;
217
218 /* Okay so far so good, lets get this into a SigMatch
219 * and put it in the Signature. */
220 sm = SigMatchAlloc();
221 if (sm == NULL)
222 goto error;
223
224 sm->type = DETECT_AL_SSH_SOFTWAREVERSION;
225 sm->ctx = (void *)ssh;
226
227 SigMatchAppendAppLayer(s, sm);
228
229 if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_SSH) {
230 SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords.");
231 goto error;
232 }
233
234 s->alproto = ALPROTO_SSH;
235 return 0;
236
237 error:
238 if (ssh != NULL) DetectSshSoftwareVersionFree(ssh);
239 if (sm != NULL) SCFree(sm);
240 return -1;
241
242 }
243
244 /**
245 * \brief this function will free memory associated with DetectSshSoftwareVersionData
246 *
247 * \param id_d pointer to DetectSshSoftwareVersionData
248 */
249 void DetectSshSoftwareVersionFree(void *ptr) {
250 DetectSshSoftwareVersionData *id_d = (DetectSshSoftwareVersionData *)ptr;
251 SCFree(id_d);
252 }
253
254 #ifdef UNITTESTS /* UNITTESTS */
255
256 /**
257 * \test DetectSshSoftwareVersionTestParse01 is a test to make sure that we parse
258 * a software version correctly
259 */
260 int DetectSshSoftwareVersionTestParse01 (void) {
261 DetectSshSoftwareVersionData *ssh = NULL;
262 ssh = DetectSshSoftwareVersionParse("PuTTY_1.0");
263 if (ssh != NULL && strncmp((char *) ssh->software_ver, "PuTTY_1.0", 9) == 0) {
264 DetectSshSoftwareVersionFree(ssh);
265 return 1;
266 }
267
268 return 0;
269 }
270
271 /**
272 * \test DetectSshSoftwareVersionTestParse02 is a test to make sure that we parse
273 * the software version correctly
274 */
275 int DetectSshSoftwareVersionTestParse02 (void) {
276 DetectSshSoftwareVersionData *ssh = NULL;
277 ssh = DetectSshSoftwareVersionParse("\"SecureCRT-4.0\"");
278 if (ssh != NULL && strncmp((char *) ssh->software_ver, "SecureCRT-4.0", 13) == 0) {
279 DetectSshSoftwareVersionFree(ssh);
280 return 1;
281 }
282
283 return 0;
284 }
285
286 /**
287 * \test DetectSshSoftwareVersionTestParse03 is a test to make sure that we
288 * don't return a ssh_data with an empty value specified
289 */
290 int DetectSshSoftwareVersionTestParse03 (void) {
291 DetectSshSoftwareVersionData *ssh = NULL;
292 ssh = DetectSshSoftwareVersionParse("");
293 if (ssh != NULL) {
294 DetectSshSoftwareVersionFree(ssh);
295 return 0;
296 }
297
298 return 1;
299 }
300
301
302 #include "stream-tcp-reassemble.h"
303
304 /** \test Send a get request in three chunks + more data. */
305 static int DetectSshSoftwareVersionTestDetect01(void) {
306 int result = 0;
307 Flow f;
308 uint8_t sshbuf1[] = "SSH-1.";
309 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
310 uint8_t sshbuf2[] = "10-PuTTY_2.123" ;
311 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
312 uint8_t sshbuf3[] = "\n";
313 uint32_t sshlen3 = sizeof(sshbuf3) - 1;
314 uint8_t sshbuf4[] = "whatever...";
315 uint32_t sshlen4 = sizeof(sshbuf4) - 1;
316 TcpSession ssn;
317 Packet *p = NULL;
318 Signature *s = NULL;
319 ThreadVars th_v;
320 DetectEngineThreadCtx *det_ctx = NULL;
321
322 memset(&th_v, 0, sizeof(th_v));
323 memset(&f, 0, sizeof(f));
324 memset(&ssn, 0, sizeof(ssn));
325
326 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
327
328 FLOW_INITIALIZE(&f);
329 f.protoctx = (void *)&ssn;
330 p->flow = &f;
331 p->flowflags |= FLOW_PKT_TOSERVER;
332 p->flowflags |= FLOW_PKT_ESTABLISHED;
333 f.alproto = ALPROTO_SSH;
334
335 StreamTcpInitConfig(TRUE);
336 FlowL7DataPtrInit(&f);
337
338 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
339 if (de_ctx == NULL) {
340 goto end;
341 }
342
343 de_ctx->flags |= DE_QUIET;
344
345 s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:PuTTY_2.123; sid:1;)");
346 if (s == NULL) {
347 goto end;
348 }
349
350 SigGroupBuild(de_ctx);
351 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
352
353 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
354 if (r != 0) {
355 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
356 goto end;
357 }
358
359 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
360 if (r != 0) {
361 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
362 goto end;
363 }
364
365 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
366 if (r != 0) {
367 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
368 goto end;
369 }
370
371 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4);
372 if (r != 0) {
373 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
374 goto end;
375 }
376
377 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
378 if (ssh_state == NULL) {
379 printf("no ssh state: ");
380 goto end;
381 }
382
383 /* do detect */
384 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
385
386 if ( !(PacketAlertCheck(p, 1))) {
387 printf("Error, the sig should match: ");
388 goto end;
389 }
390
391 result = 1;
392 end:
393 SigGroupCleanup(de_ctx);
394 SigCleanSignatures(de_ctx);
395
396 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
397 DetectEngineCtxFree(de_ctx);
398
399 FlowL7DataPtrFree(&f);
400 StreamTcpFreeConfig(TRUE);
401 FLOW_DESTROY(&f);
402
403 UTHFreePackets(&p, 1);
404 return result;
405 }
406
407 /** \test Send a get request in three chunks + more data. */
408 static int DetectSshSoftwareVersionTestDetect02(void) {
409 int result = 0;
410 Flow f;
411 uint8_t sshbuf1[] = "SSH-1.99-Pu";
412 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
413 uint8_t sshbuf2[] = "TTY_2.123" ;
414 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
415 uint8_t sshbuf3[] = "\n";
416 uint32_t sshlen3 = sizeof(sshbuf3) - 1;
417 uint8_t sshbuf4[] = "whatever...";
418 uint32_t sshlen4 = sizeof(sshbuf4) - 1;
419 TcpSession ssn;
420 Packet *p = NULL;
421 Signature *s = NULL;
422 ThreadVars th_v;
423 DetectEngineThreadCtx *det_ctx = NULL;
424
425 memset(&th_v, 0, sizeof(th_v));
426 memset(&f, 0, sizeof(f));
427 memset(&ssn, 0, sizeof(ssn));
428
429 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
430
431 FLOW_INITIALIZE(&f);
432 f.protoctx = (void *)&ssn;
433 p->flow = &f;
434 p->flowflags |= FLOW_PKT_TOSERVER;
435 p->flowflags |= FLOW_PKT_ESTABLISHED;
436 f.alproto = ALPROTO_SSH;
437
438 StreamTcpInitConfig(TRUE);
439 FlowL7DataPtrInit(&f);
440
441 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
442 if (de_ctx == NULL) {
443 goto end;
444 }
445
446 de_ctx->flags |= DE_QUIET;
447
448 s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:PuTTY_2.123; sid:1;)");
449 if (s == NULL) {
450 goto end;
451 }
452
453 SigGroupBuild(de_ctx);
454 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
455
456 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
457 if (r != 0) {
458 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
459 goto end;
460 }
461
462 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
463 if (r != 0) {
464 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
465 goto end;
466 }
467
468 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
469 if (r != 0) {
470 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
471 goto end;
472 }
473
474 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4);
475 if (r != 0) {
476 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
477 goto end;
478 }
479
480 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
481 if (ssh_state == NULL) {
482 printf("no ssh state: ");
483 goto end;
484 }
485
486 /* do detect */
487 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
488
489 if ( !(PacketAlertCheck(p, 1))) {
490 printf("Error, the sig should match: ");
491 goto end;
492 }
493
494 result = 1;
495 end:
496 SigGroupCleanup(de_ctx);
497 SigCleanSignatures(de_ctx);
498
499 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
500 DetectEngineCtxFree(de_ctx);
501
502 FlowL7DataPtrFree(&f);
503 StreamTcpFreeConfig(TRUE);
504 FLOW_DESTROY(&f);
505
506 UTHFreePackets(&p, 1);
507 return result;
508 }
509
510 /** \test Send a get request in three chunks + more data. */
511 static int DetectSshSoftwareVersionTestDetect03(void) {
512 int result = 0;
513 Flow f;
514 uint8_t sshbuf1[] = "SSH-1.";
515 uint32_t sshlen1 = sizeof(sshbuf1) - 1;
516 uint8_t sshbuf2[] = "7-PuTTY_2.123" ;
517 uint32_t sshlen2 = sizeof(sshbuf2) - 1;
518 uint8_t sshbuf3[] = "\n";
519 uint32_t sshlen3 = sizeof(sshbuf3) - 1;
520 uint8_t sshbuf4[] = "whatever...";
521 uint32_t sshlen4 = sizeof(sshbuf4) - 1;
522 TcpSession ssn;
523 Packet *p = NULL;
524 Signature *s = NULL;
525 ThreadVars th_v;
526 DetectEngineThreadCtx *det_ctx = NULL;
527
528 memset(&th_v, 0, sizeof(th_v));
529 memset(&f, 0, sizeof(f));
530 memset(&ssn, 0, sizeof(ssn));
531
532 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
533
534 FLOW_INITIALIZE(&f);
535 f.protoctx = (void *)&ssn;
536 p->flow = &f;
537 p->flowflags |= FLOW_PKT_TOSERVER;
538 p->flowflags |= FLOW_PKT_ESTABLISHED;
539 f.alproto = ALPROTO_SSH;
540
541 StreamTcpInitConfig(TRUE);
542 FlowL7DataPtrInit(&f);
543
544 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
545 if (de_ctx == NULL) {
546 goto end;
547 }
548
549 de_ctx->flags |= DE_QUIET;
550
551 s = de_ctx->sig_list = SigInit(de_ctx,"alert ssh any any -> any any (msg:\"SSH\"; ssh.softwareversion:lalala-3.1.4; sid:1;)");
552 if (s == NULL) {
553 goto end;
554 }
555
556 SigGroupBuild(de_ctx);
557 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
558
559 int r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
560 if (r != 0) {
561 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
562 goto end;
563 }
564
565 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
566 if (r != 0) {
567 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
568 goto end;
569 }
570
571 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
572 if (r != 0) {
573 printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
574 goto end;
575 }
576
577 r = AppLayerParse(&f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4);
578 if (r != 0) {
579 printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
580 goto end;
581 }
582
583 SshState *ssh_state = f.aldata[AlpGetStateIdx(ALPROTO_SSH)];
584 if (ssh_state == NULL) {
585 printf("no ssh state: ");
586 goto end;
587 }
588
589 /* do detect */
590 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
591
592 if (PacketAlertCheck(p, 1)) {
593 printf("Error, 1.7 version is not 2 compat, so the sig should not match: ");
594 goto end;
595 }
596
597 result = 1;
598 end:
599 SigGroupCleanup(de_ctx);
600 SigCleanSignatures(de_ctx);
601
602 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
603 DetectEngineCtxFree(de_ctx);
604
605 FlowL7DataPtrFree(&f);
606 StreamTcpFreeConfig(TRUE);
607 FLOW_DESTROY(&f);
608
609 UTHFreePackets(&p, 1);
610 return result;
611 }
612
613 #endif /* UNITTESTS */
614
615 /**
616 * \brief this function registers unit tests for DetectSshSoftwareVersion
617 */
618 void DetectSshSoftwareVersionRegisterTests(void) {
619 #ifdef UNITTESTS /* UNITTESTS */
620 UtRegisterTest("DetectSshSoftwareVersionTestParse01", DetectSshSoftwareVersionTestParse01, 1);
621 UtRegisterTest("DetectSshSoftwareVersionTestParse02", DetectSshSoftwareVersionTestParse02, 1);
622 UtRegisterTest("DetectSshSoftwareVersionTestParse03", DetectSshSoftwareVersionTestParse03, 1);
623 UtRegisterTest("DetectSshSoftwareVersionTestDetect01", DetectSshSoftwareVersionTestDetect01, 1);
624 UtRegisterTest("DetectSshSoftwareVersionTestDetect02", DetectSshSoftwareVersionTestDetect02, 1);
625 UtRegisterTest("DetectSshSoftwareVersionTestDetect03", DetectSshSoftwareVersionTestDetect03, 1);
626 #endif /* UNITTESTS */
627 }
628
0 /* Copyright (C) 2007-2010 Open Information Security Foundation
1 *
2 * You can copy, redistribute or modify this Program under the terms of
3 * the GNU General Public License version 2 as published by the Free
4 * Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * version 2 along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
14 * 02110-1301, USA.
15 */
16
17 /**
18 * \file
19 *
20 * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
21 */
22
23 #ifndef __DETECT_SSH_SOFTWARE_VERSION_H__
24 #define __DETECT_SSH_SOFTWARE_VERSION_H__
25
26 typedef struct DetectSshSoftwareVersionData_ {
27 uint8_t *software_ver; /** ssh version to match */
28 uint16_t len; /** ssh version length to match */
29 } DetectSshSoftwareVersionData;
30
31 /* prototypes */
32 void DetectSshSoftwareVersionRegister(void);
33 void DetectSshSoftwareVersionRegisterTests(void);
34
35 #endif /* __DETECT_SSH_SOFTWARE_VERSION_H__ */
36
155155 &s->pmatch, &s->pmatch_tail,
156156 &s->dmatch, &s->dmatch_tail);
157157 pm = pm1;
158 } else if (pm2_ots->idx > dcem->idx) {
158 } else {
159159 /* within is against pm1, pm = pm1 */
160160 pm = pm1;
161161 }
5050 #include "detect-http-method.h"
5151
5252 #include "detect-decode-event.h"
53 #include "decode.h"
5354
5455 #include "detect-ipopts.h"
5556 #include "detect-flags.h"
118119 #include "app-layer-protos.h"
119120 #include "app-layer-htp.h"
120121 #include "detect-tls-version.h"
122 #include "detect-ssh-proto-version.h"
123 #include "detect-ssh-software-version.h"
121124
122125 #include "action-globals.h"
123126 #include "tm-modules.h"
143146 #include "util-privs.h"
144147 #include "util-profiling.h"
145148 #include "util-validate.h"
149
150 extern uint8_t engine_mode;
146151
147152 SigMatch *SigMatchAlloc(void);
148153 void DetectExitPrintStats(ThreadVars *tv, void *data);
688693 */
689694 int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
690695 {
696
697
698 /* No need to perform any detection on this packet, if the the given flag is set.*/
699 if (p->flags & PKT_NOPACKET_INSPECTION)
700 return 0;
701
691702 int match = 0, fmatch = 0;
692703 Signature *s = NULL;
693704 SigMatch *sm = NULL;
700711 char use_flow_sgh = FALSE;
701712 StreamMsg *smsg = NULL;
702713 char no_store_flow_sgh = FALSE;
714 uint8_t alert_flags = 0;
703715
704716 SCEnter();
705717
779791 /* if it matched a "pass" rule, we have to let it go */
780792 p->action |= ACTION_PASS;
781793 }
782 if (p->flow->flags & FLOW_ACTION_DROP) p->action |= ACTION_DROP;
794 /* If we have a drop from IP only module,
795 * we will drop the rest of the flow packets
796 * This will apply only to inline/IPS */
797 if (p->flow != NULL &&
798 (p->flow->flags & FLOW_ACTION_DROP))
799 {
800 alert_flags = PACKET_ALERT_FLAG_DROP_FLOW;
801 p->action |= ACTION_DROP;
802 }
783803 } else {
784804 /* Even without flow we should match the packet src/dst */
785805 IPOnlyMatchPacket(de_ctx, det_ctx, &de_ctx->io_ctx, &det_ctx->io_ctx, p);
939959 if (DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, p->flow, smsg_inspect->data.data, smsg_inspect->data.data_len) == 1) {
940960 SCLogDebug("match in smsg %p", smsg);
941961 pmatch = 1;
962 /* Tell the enigne that this reassembled stream can drop the
963 * rest of the pkts with no further inspection */
964 if (s->action == ACTION_DROP)
965 alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW;
942966 break;
943967 }
944968 }
969993 if (det_ctx->de_state_sig_array[s->num] == DE_STATE_MATCH_NOSTATE) {
970994 SCLogDebug("stateful app layer match inspection starting");
971995 if (DeStateDetectStartDetection(th_v, de_ctx, det_ctx, s,
972 p->flow, flags, alstate, alproto) != 1)
996 p->flow, flags, alstate, alproto) != 1) {
973997 goto next;
998 } else {
999 if (s->action == ACTION_DROP)
1000 alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW;
1001 }
9741002 } else {
9751003 SCLogDebug("already having a destate");
9761004
9781006 s->id, (uintmax_t)s->num, DeStateMatchResultToString(det_ctx->de_state_sig_array[s->num]));
9791007 if (det_ctx->de_state_sig_array[s->num] != DE_STATE_MATCH_NEW) {
9801008 goto next;
1009 } else {
1010 if (s->action == ACTION_DROP)
1011 alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW;
9811012 }
9821013 }
9831014 }
9891020
9901021 fmatch = 1;
9911022 if (!(s->flags & SIG_FLAG_NOALERT)) {
992 PacketAlertAppend(det_ctx, s, p);
1023 PacketAlertAppend(det_ctx, s, p, alert_flags);
9931024 }
9941025 } else {
9951026 if (s->flags & SIG_FLAG_RECURSIVE) {
10091040 if (!(s->flags & SIG_FLAG_NOALERT)) {
10101041 /* only add once */
10111042 if (rmatch == 0) {
1012 PacketAlertAppend(det_ctx, s, p);
1043 PacketAlertAppend(det_ctx, s, p, alert_flags);
10131044 }
10141045 }
10151046 rmatch = fmatch = 1;
10421073 if (sm == NULL) {
10431074 fmatch = 1;
10441075 if (!(s->flags & SIG_FLAG_NOALERT)) {
1045 PacketAlertAppend(det_ctx, s, p);
1076 PacketAlertAppend(det_ctx, s, p, alert_flags);
10461077 }
10471078 }
10481079 } else {
33553386 DetectHttpClientBodyRegister();
33563387 DetectHttpUriRegister();
33573388 DetectAsn1Register();
3389 DetectSshVersionRegister();
3390 DetectSshSoftwareVersionRegister();
33583391
33593392 uint8_t i = 0;
33603393 for (i = 0; i < DETECT_TBLSIZE; i++) {
50875120
50885121 Packet p1, p2;
50895122 ThreadVars th_v;
5090 DetectEngineThreadCtx *det_ctx;
5123 DetectEngineThreadCtx *det_ctx = NULL;
50915124 int result = 0;
50925125
50935126 uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n"
88238856 return result;
88248857 }
88258858
8859 /** \test test if the engine set flag to drop pkts of a flow that
8860 * triggered a drop action on IPS mode */
8861 static int SigTestDropFlow01(void)
8862 {
8863 int result = 0;
8864 Flow f;
8865 HtpState *http_state = NULL;
8866 uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
8867 "User-Agent: Mozilla/1.0\r\n"
8868 "Cookie: hellocatch\r\n\r\n";
8869 uint32_t http_buf1_len = sizeof(http_buf1) - 1;
8870 TcpSession ssn;
8871 Packet *p = NULL;
8872 Signature *s = NULL;
8873 ThreadVars tv;
8874 DetectEngineThreadCtx *det_ctx = NULL;
8875
8876 memset(&tv, 0, sizeof(ThreadVars));
8877 memset(&f, 0, sizeof(Flow));
8878 memset(&ssn, 0, sizeof(TcpSession));
8879
8880 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
8881
8882 FLOW_INITIALIZE(&f);
8883 f.protoctx = (void *)&ssn;
8884 f.src.family = AF_INET;
8885 f.dst.family = AF_INET;
8886
8887 p->flow = &f;
8888 p->flowflags |= FLOW_PKT_TOSERVER;
8889 p->flowflags |= FLOW_PKT_ESTABLISHED;
8890 f.alproto = ALPROTO_HTTP;
8891
8892 StreamTcpInitConfig(TRUE);
8893 FlowL7DataPtrInit(&f);
8894
8895 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
8896 if (de_ctx == NULL) {
8897 goto end;
8898 }
8899 de_ctx->mpm_matcher = MPM_B2G;
8900 de_ctx->flags |= DE_QUIET;
8901
8902 s = de_ctx->sig_list = SigInit(de_ctx, "drop http any any -> any any "
8903 "(msg:\"Test proto match\"; "
8904 "sid:1;)");
8905 if (s == NULL) {
8906 goto end;
8907 }
8908
8909 SigGroupBuild(de_ctx);
8910 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
8911
8912 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len);
8913 if (r != 0) {
8914 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
8915 goto end;
8916 }
8917
8918 http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
8919 if (http_state == NULL) {
8920 printf("no http state: ");
8921 goto end;
8922 }
8923
8924 /* do detect */
8925 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
8926
8927 if (!PacketAlertCheck(p, 1)) {
8928 printf("sig 1 didn't alert, but it should: ");
8929 goto end;
8930 }
8931
8932 if ( !(p->flow->flags & FLOW_ACTION_DROP)) {
8933 printf("sig 1 alerted but flow was not flagged correctly: ");
8934 goto end;
8935 }
8936
8937 /* Ok, now we know that the flag is set for proto http */
8938
8939 result = 1;
8940
8941 end:
8942 if (det_ctx != NULL)
8943 DetectEngineThreadCtxDeinit(&tv, det_ctx);
8944 if (de_ctx != NULL)
8945 SigGroupCleanup(de_ctx);
8946 if (de_ctx != NULL)
8947 DetectEngineCtxFree(de_ctx);
8948
8949 StreamTcpFreeConfig(TRUE);
8950 FLOW_DESTROY(&f);
8951
8952 UTHFreePackets(&p, 1);
8953 return result;
8954 }
8955
8956 /** \test test if the engine set flag to drop pkts of a flow that
8957 * triggered a drop action on IPS mode */
8958 static int SigTestDropFlow02(void)
8959 {
8960 int result = 0;
8961 Flow f;
8962 HtpState *http_state = NULL;
8963 uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
8964 "User-Agent: Mozilla/1.0\r\n"
8965 "Cookie: hellocatch\r\n\r\n";
8966 uint32_t http_buf1_len = sizeof(http_buf1) - 1;
8967 TcpSession ssn;
8968 Packet *p = NULL;
8969 Signature *s = NULL;
8970 ThreadVars tv;
8971 DetectEngineThreadCtx *det_ctx = NULL;
8972
8973 memset(&tv, 0, sizeof(ThreadVars));
8974 memset(&f, 0, sizeof(Flow));
8975 memset(&ssn, 0, sizeof(TcpSession));
8976
8977 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
8978
8979 FLOW_INITIALIZE(&f);
8980 f.protoctx = (void *)&ssn;
8981 f.src.family = AF_INET;
8982 f.dst.family = AF_INET;
8983
8984 p->flow = &f;
8985 p->flowflags |= FLOW_PKT_TOSERVER;
8986 p->flowflags |= FLOW_PKT_ESTABLISHED;
8987 f.alproto = ALPROTO_HTTP;
8988
8989 StreamTcpInitConfig(TRUE);
8990 FlowL7DataPtrInit(&f);
8991
8992 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
8993 if (de_ctx == NULL) {
8994 goto end;
8995 }
8996 de_ctx->mpm_matcher = MPM_B2G;
8997 de_ctx->flags |= DE_QUIET;
8998
8999 s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 "
9000 "(msg:\"Test proto match\"; uricontent:\"one\";"
9001 "sid:1;)");
9002 if (s == NULL) {
9003 goto end;
9004 }
9005
9006 SigGroupBuild(de_ctx);
9007 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
9008
9009 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len);
9010 if (r != 0) {
9011 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
9012 goto end;
9013 }
9014
9015 http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
9016 if (http_state == NULL) {
9017 printf("no http state: ");
9018 goto end;
9019 }
9020
9021 /* do detect */
9022 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
9023
9024 if (!PacketAlertCheck(p, 1)) {
9025 printf("sig 1 didn't alert, but it should: ");
9026 goto end;
9027 }
9028
9029 if ( !(p->flow->flags & FLOW_ACTION_DROP)) {
9030 printf("sig 1 alerted but flow was not flagged correctly: ");
9031 goto end;
9032 }
9033
9034 /* Ok, now we know that the flag is set for app layer sigs
9035 * (ex: inspecting uricontent) */
9036
9037 result = 1;
9038
9039 end:
9040 if (det_ctx != NULL)
9041 DetectEngineThreadCtxDeinit(&tv, det_ctx);
9042 if (de_ctx != NULL)
9043 SigGroupCleanup(de_ctx);
9044 if (de_ctx != NULL)
9045 DetectEngineCtxFree(de_ctx);
9046
9047 StreamTcpFreeConfig(TRUE);
9048 FLOW_DESTROY(&f);
9049
9050 UTHFreePackets(&p, 1);
9051 return result;
9052 }
9053
9054 /** \test test if the engine set flag to drop pkts of a flow that
9055 * triggered a drop action on IPS mode, and it doesn't inspect
9056 * any other packet of the stream */
9057 static int SigTestDropFlow03(void)
9058 {
9059 int result = 0;
9060 Flow f;
9061 HtpState *http_state = NULL;
9062 uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
9063 "User-Agent: Mozilla/1.0\r\n"
9064 "Cookie: hellocatch\r\n\r\n";
9065 uint32_t http_buf1_len = sizeof(http_buf1) - 1;
9066
9067 uint8_t http_buf2[] = "POST /two HTTP/1.0\r\n"
9068 "User-Agent: Mozilla/1.0\r\n"
9069 "Cookie: hellocatch\r\n\r\n";
9070 uint32_t http_buf2_len = sizeof(http_buf1) - 1;
9071
9072 /* Set the engine mode to IPS */
9073 SET_ENGINE_MODE_IPS(engine_mode);
9074
9075 TcpSession ssn;
9076 Packet *p1 = NULL;
9077 Packet *p2 = NULL;
9078 Signature *s = NULL;
9079 ThreadVars tv;
9080 DetectEngineThreadCtx *det_ctx = NULL;
9081
9082 memset(&tv, 0, sizeof(ThreadVars));
9083 memset(&f, 0, sizeof(Flow));
9084 memset(&ssn, 0, sizeof(TcpSession));
9085
9086 p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
9087 p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
9088
9089 FLOW_INITIALIZE(&f);
9090 f.protoctx = (void *)&ssn;
9091 f.src.family = AF_INET;
9092 f.dst.family = AF_INET;
9093
9094 p1->flow = &f;
9095 p1->flowflags |= FLOW_PKT_TOSERVER;
9096 p1->flowflags |= FLOW_PKT_ESTABLISHED;
9097
9098 p2->flow = &f;
9099 p2->flowflags |= FLOW_PKT_TOSERVER;
9100 p2->flowflags |= FLOW_PKT_ESTABLISHED;
9101 f.alproto = ALPROTO_HTTP;
9102
9103 StreamTcpInitConfig(TRUE);
9104 FlowL7DataPtrInit(&f);
9105
9106 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
9107 if (de_ctx == NULL) {
9108 goto end;
9109 }
9110
9111 de_ctx->mpm_matcher = MPM_B2G;
9112 de_ctx->flags |= DE_QUIET;
9113
9114 s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 "
9115 "(msg:\"Test proto match\"; uricontent:\"one\";"
9116 "sid:1;)");
9117 if (s == NULL) {
9118 goto end;
9119 }
9120
9121 /* the no inspection flag should be set after the first sig gets triggered,
9122 * so the second packet should not match the next sig (because of no inspection) */
9123 s = de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any 80 "
9124 "(msg:\"Test proto match\"; uricontent:\"two\";"
9125 "sid:2;)");
9126 if (s == NULL) {
9127 goto end;
9128 }
9129
9130 SigGroupBuild(de_ctx);
9131 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
9132
9133 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len);
9134 if (r != 0) {
9135 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
9136 goto end;
9137 }
9138
9139 http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
9140 if (http_state == NULL) {
9141 printf("no http state: ");
9142 goto end;
9143 }
9144
9145 /* do detect */
9146 SigMatchSignatures(&tv, de_ctx, det_ctx, p1);
9147
9148 if (!PacketAlertCheck(p1, 1)) {
9149 printf("sig 1 didn't alert on p1, but it should: ");
9150 goto end;
9151 }
9152
9153 if ( !(p1->flow->flags & FLOW_ACTION_DROP)) {
9154 printf("sig 1 alerted but flow was not flagged correctly: ");
9155 goto end;
9156 }
9157
9158 /* Second part.. Let's feed with another packet */
9159 if (StreamTcpCheckFlowDrops(p2) == 1) {
9160 SCLogDebug("This flow/stream triggered a drop rule");
9161 FlowSetNoPacketInspectionFlag(p2->flow);
9162 DecodeSetNoPacketInspectionFlag(p2);
9163 FlowSetSessionNoApplayerInspectionFlag(p2->flow);
9164 p2->action |= ACTION_DROP;
9165 /* return the segments to the pool */
9166 StreamTcpSessionPktFree(p2);
9167 }
9168
9169
9170 if ( !(p2->flags & PKT_NOPACKET_INSPECTION)) {
9171 printf("The packet was not flagged with no-inspection: ");
9172 goto end;
9173 }
9174
9175 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len);
9176 if (r != 0) {
9177 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
9178 goto end;
9179 }
9180
9181 /* do detect */
9182 SigMatchSignatures(&tv, de_ctx, det_ctx, p2);
9183
9184 if (PacketAlertCheck(p2, 1)) {
9185 printf("sig 1 alerted, but it should not since the no pkt inspection should be set: ");
9186 goto end;
9187 }
9188
9189 if (PacketAlertCheck(p2, 2)) {
9190 printf("sig 2 alerted, but it should not since the no pkt inspection should be set: ");
9191 goto end;
9192 }
9193
9194 if ( !(p2->action & ACTION_DROP)) {
9195 printf("A \"drop\" action should be set from the flow to the packet: ");
9196 goto end;
9197 }
9198
9199 result = 1;
9200
9201 end:
9202 if (det_ctx != NULL)
9203 DetectEngineThreadCtxDeinit(&tv, det_ctx);
9204 if (de_ctx != NULL)
9205 SigGroupCleanup(de_ctx);
9206 if (de_ctx != NULL)
9207 DetectEngineCtxFree(de_ctx);
9208
9209 StreamTcpFreeConfig(TRUE);
9210 FLOW_DESTROY(&f);
9211
9212 UTHFreePackets(&p1, 1);
9213 UTHFreePackets(&p2, 1);
9214
9215 /* Restore mode to IDS */
9216 SET_ENGINE_MODE_IDS(engine_mode);
9217 return result;
9218 }
9219
9220 /** \test test if the engine set flag to drop pkts of a flow that
9221 * triggered a drop action on IDS mode, but continue the inspection
9222 * as usual (instead of on IPS mode) */
9223 static int SigTestDropFlow04(void)
9224 {
9225 int result = 0;
9226 Flow f;
9227 HtpState *http_state = NULL;
9228 uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
9229 "User-Agent: Mozilla/1.0\r\n"
9230 "Cookie: hellocatch\r\n\r\n";
9231 uint32_t http_buf1_len = sizeof(http_buf1) - 1;
9232
9233 uint8_t http_buf2[] = "POST /two HTTP/1.0\r\n"
9234 "User-Agent: Mozilla/1.0\r\n"
9235 "Cookie: hellocatch\r\n\r\n";
9236 uint32_t http_buf2_len = sizeof(http_buf1) - 1;
9237
9238 TcpSession ssn;
9239 Packet *p1 = NULL;
9240 Packet *p2 = NULL;
9241 Signature *s = NULL;
9242 ThreadVars tv;
9243 DetectEngineThreadCtx *det_ctx = NULL;
9244
9245 memset(&tv, 0, sizeof(ThreadVars));
9246 memset(&f, 0, sizeof(Flow));
9247 memset(&ssn, 0, sizeof(TcpSession));
9248
9249 p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
9250 p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
9251
9252 FLOW_INITIALIZE(&f);
9253 f.protoctx = (void *)&ssn;
9254 f.src.family = AF_INET;
9255 f.dst.family = AF_INET;
9256
9257 p1->flow = &f;
9258 p1->flowflags |= FLOW_PKT_TOSERVER;
9259 p1->flowflags |= FLOW_PKT_ESTABLISHED;
9260
9261 p2->flow = &f;
9262 p2->flowflags |= FLOW_PKT_TOSERVER;
9263 p2->flowflags |= FLOW_PKT_ESTABLISHED;
9264 f.alproto = ALPROTO_HTTP;
9265
9266 StreamTcpInitConfig(TRUE);
9267 FlowL7DataPtrInit(&f);
9268
9269 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
9270 if (de_ctx == NULL) {
9271 goto end;
9272 }
9273 de_ctx->mpm_matcher = MPM_B2G;
9274 de_ctx->flags |= DE_QUIET;
9275
9276 s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 "
9277 "(msg:\"Test proto match\"; uricontent:\"one\";"
9278 "sid:1;)");
9279 if (s == NULL) {
9280 goto end;
9281 }
9282
9283 /* the no inspection flag should be set after the first sig gets triggered,
9284 * so the second packet should not match the next sig (because of no inspection) */
9285 s = de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any 80 "
9286 "(msg:\"Test proto match\"; uricontent:\"two\";"
9287 "sid:2;)");
9288 if (s == NULL) {
9289 goto end;
9290 }
9291
9292 SigGroupBuild(de_ctx);
9293 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
9294
9295 int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len);
9296 if (r != 0) {
9297 printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
9298 goto end;
9299 }
9300
9301 http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
9302 if (http_state == NULL) {
9303 printf("no http state: ");
9304 goto end;
9305 }
9306
9307 /* do detect */
9308 SigMatchSignatures(&tv, de_ctx, det_ctx, p1);
9309
9310 if (!PacketAlertCheck(p1, 1)) {
9311 printf("sig 1 didn't alert on p1, but it should: ");
9312 goto end;
9313 }
9314
9315 if ( !(p1->flow->flags & FLOW_ACTION_DROP)) {
9316 printf("sig 1 alerted but flow was not flagged correctly: ");
9317 goto end;
9318 }
9319
9320 /* Second part.. Let's feed with another packet */
9321 if (StreamTcpCheckFlowDrops(p2) == 1) {
9322 FlowSetNoPacketInspectionFlag(p2->flow);
9323 DecodeSetNoPacketInspectionFlag(p2);
9324 FlowSetSessionNoApplayerInspectionFlag(p2->flow);
9325 p2->action |= ACTION_DROP;
9326 /* return the segments to the pool */
9327 StreamTcpSessionPktFree(p2);
9328 }
9329
9330 if ( (p2->flags & PKT_NOPACKET_INSPECTION)) {
9331 printf("The packet was flagged with no-inspection but we are not on IPS mode: ");
9332 goto end;
9333 }
9334
9335 r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len);
9336 if (r != 0) {
9337 printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
9338 goto end;
9339 }
9340
9341 /* do detect */
9342 SigMatchSignatures(&tv, de_ctx, det_ctx, p2);
9343
9344 if (PacketAlertCheck(p2, 1)) {
9345 printf("sig 1 alerted, but it should not since the no pkt inspection should be set: ");
9346 goto end;
9347 }
9348
9349 if (!PacketAlertCheck(p2, 2)) {
9350 printf("sig 2 didn't alert, but it should, since we are not on IPS mode: ");
9351 goto end;
9352 }
9353
9354 if (p2->action & ACTION_DROP) {
9355 printf("A \"drop\" action was set from the flow to the packet, but on IDS mode it whould not (it should be inspected as usual: ");
9356 goto end;
9357 }
9358
9359 result = 1;
9360
9361 end:
9362 if (det_ctx != NULL)
9363 DetectEngineThreadCtxDeinit(&tv, det_ctx);
9364 if (de_ctx != NULL)
9365 SigGroupCleanup(de_ctx);
9366 if (de_ctx != NULL)
9367 DetectEngineCtxFree(de_ctx);
9368
9369 StreamTcpFreeConfig(TRUE);
9370 FLOW_DESTROY(&f);
9371
9372 UTHFreePackets(&p1, 1);
9373 UTHFreePackets(&p2, 1);
9374
9375 return result;
9376 }
9377
88269378 #endif /* UNITTESTS */
88279379
88289380 void SigRegisterTests(void) {
90259577
90269578 UtRegisterTest("SigTestDetectAlertCounter", SigTestDetectAlertCounter, 1);
90279579
9580 UtRegisterTest("SigTestDropFlow01", SigTestDropFlow01, 1);
9581 UtRegisterTest("SigTestDropFlow02", SigTestDropFlow02, 1);
9582 UtRegisterTest("SigTestDropFlow03", SigTestDropFlow03, 1);
9583 UtRegisterTest("SigTestDropFlow04", SigTestDropFlow04, 1);
9584
90289585 #endif /* UNITTESTS */
90299586 }
90309587
741741 DETECT_URICONTENT,
742742 DETECT_PCRE,
743743 DETECT_PCRE_HTTPBODY,
744 DETECT_PCRE_HTTPCOOKIE,
745 DETECT_PCRE_HTTPHEADER,
746 DETECT_PCRE_HTTPMETHOD,
744747 DETECT_ACK,
745748 DETECT_SEQ,
746749 DETECT_DEPTH,
800803 DETECT_AL_HTTP_CLIENT_BODY,
801804 DETECT_AL_HTTP_HEADER,
802805 DETECT_AL_HTTP_URI,
806 DETECT_AL_SSH_PROTOVERSION,
807 DETECT_AL_SSH_SOFTWAREVERSION,
803808
804809 DETECT_DCE_IFACE,
805810 DETECT_DCE_OPNUM,
14311431 return 1;
14321432 }
14331433
1434 /** \brief Set the No Packet Inspection Flag after locking the flow.
1435 *
1436 * \param f Flow to set the flag in
1437 */
1438 void FlowLockSetNoPacketInspectionFlag(Flow *f) {
1439 SCEnter();
1440
1441 SCLogDebug("flow %p", f);
1442 SCMutexLock(&f->m);
1443 f->flags |= FLOW_NOPACKET_INSPECTION;
1444 SCMutexUnlock(&f->m);
1445
1446 SCReturn;
1447 }
1448
1449 /** \brief Set the No Packet Inspection Flag without locking the flow.
1450 *
1451 * \param f Flow to set the flag in
1452 */
1453 void FlowSetNoPacketInspectionFlag(Flow *f) {
1454 SCEnter();
1455
1456 SCLogDebug("flow %p", f);
1457 f->flags |= FLOW_NOPACKET_INSPECTION;
1458
1459 SCReturn;
1460 }
1461
1462 /** \brief Set the No payload inspection Flag after locking the flow.
1463 *
1464 * \param f Flow to set the flag in
1465 */
1466 void FlowLockSetNoPayloadInspectionFlag(Flow *f) {
1467 SCEnter();
1468
1469 SCLogDebug("flow %p", f);
1470 SCMutexLock(&f->m);
1471 f->flags |= FLOW_NOPAYLOAD_INSPECTION;
1472 SCMutexUnlock(&f->m);
1473
1474 SCReturn;
1475 }
1476
1477 /** \brief Set the No payload inspection Flag without locking the flow.
1478 *
1479 * \param f Flow to set the flag in
1480 */
1481 void FlowSetNoPayloadInspectionFlag(Flow *f) {
1482 SCEnter();
1483
1484 SCLogDebug("flow %p", f);
1485 f->flags |= FLOW_NOPAYLOAD_INSPECTION;
1486
1487 SCReturn;
1488 }
1489
1490 /** \brief set flow flag to disable app layer inspection
1491 *
1492 * \param f *LOCKED* flow
1493 */
1494 void FlowSetSessionNoApplayerInspectionFlag(Flow *f) {
1495 f->alflags |= FLOW_AL_NO_APPLAYER_INSPECTION;
1496 }
1497
14981434 #ifdef UNITTESTS
14991435 #include "stream-tcp-private.h"
15001436 #include "threads.h"
253253 int FlowSetFlowStateFunc (uint8_t , int (*GetProtoState)(void *));
254254 void FlowUpdateQueue(Flow *);
255255
256 void FlowLockSetNoPacketInspectionFlag(Flow *);
257 void FlowSetNoPacketInspectionFlag(Flow *);
258 void FlowLockSetNoPayloadInspectionFlag(Flow *);
259 void FlowSetNoPayloadInspectionFlag(Flow *);
260 void FlowSetSessionNoApplayerInspectionFlag(Flow *);
256 static inline void FlowLockSetNoPacketInspectionFlag(Flow *);
257 static inline void FlowSetNoPacketInspectionFlag(Flow *);
258 static inline void FlowLockSetNoPayloadInspectionFlag(Flow *);
259 static inline void FlowSetNoPayloadInspectionFlag(Flow *);
260 static inline void FlowSetSessionNoApplayerInspectionFlag(Flow *);
261261
262262 int FlowGetPacketDirection(Flow *, Packet *);
263263
264264 void FlowL7DataPtrInit(Flow *);
265265 void FlowL7DataPtrFree(Flow *);
266266
267 /** ----- Inline functions ----- */
268
269 /** \brief Set the No Packet Inspection Flag after locking the flow.
270 *
271 * \param f Flow to set the flag in
272 */
273 static inline void FlowLockSetNoPacketInspectionFlag(Flow *f) {
274 SCEnter();
275
276 SCLogDebug("flow %p", f);
277 SCMutexLock(&f->m);
278 f->flags |= FLOW_NOPACKET_INSPECTION;
279 SCMutexUnlock(&f->m);
280
281 SCReturn;
282 }
283
284 /** \brief Set the No Packet Inspection Flag without locking the flow.
285 *
286 * \param f Flow to set the flag in
287 */
288 static inline void FlowSetNoPacketInspectionFlag(Flow *f) {
289 SCEnter();
290
291 SCLogDebug("flow %p", f);
292 f->flags |= FLOW_NOPACKET_INSPECTION;
293
294 SCReturn;
295 }
296
297 /** \brief Set the No payload inspection Flag after locking the flow.
298 *
299 * \param f Flow to set the flag in
300 */
301 static inline void FlowLockSetNoPayloadInspectionFlag(Flow *f) {
302 SCEnter();
303
304 SCLogDebug("flow %p", f);
305 SCMutexLock(&f->m);
306 f->flags |= FLOW_NOPAYLOAD_INSPECTION;
307 SCMutexUnlock(&f->m);
308
309 SCReturn;
310 }
311
312 /** \brief Set the No payload inspection Flag without locking the flow.
313 *
314 * \param f Flow to set the flag in
315 */
316 static inline void FlowSetNoPayloadInspectionFlag(Flow *f) {
317 SCEnter();
318
319 SCLogDebug("flow %p", f);
320 f->flags |= FLOW_NOPAYLOAD_INSPECTION;
321
322 SCReturn;
323 }
324
325 /** \brief set flow flag to disable app layer inspection
326 *
327 * \param f *LOCKED* flow
328 */
329 static inline void FlowSetSessionNoApplayerInspectionFlag(Flow *f) {
330 f->alflags |= FLOW_AL_NO_APPLAYER_INSPECTION;
331 }
332
333
267334 #endif /* __FLOW_H__ */
268335
15941594 /* if app layer protocol has been detected, then restore the reassembled
15951595 seq. to the value till reassembling has been done and unset the queue
15961596 init flag permanently for this tcp session */
1597 } else if (stream->tmp_ra_base_seq > stream->ra_base_seq) {
1597 } else if (SEQ_GT(stream->tmp_ra_base_seq, stream->ra_base_seq)) {
15981598 stream->ra_base_seq = stream->tmp_ra_base_seq;
15991599 ra_ctx->stream_q->flags &= ~STREAMQUEUE_FLAG_INIT;
16001600 ra_base_seq = stream->ra_base_seq;
16051605 /* set the ra_bas_seq to stream->ra_base_seq as now app layer protocol
16061606 has been detected */
16071607 } else {
1608 ra_base_seq = stream->ra_base_seq;
1608 if (SEQ_GT(stream->tmp_ra_base_seq, stream->ra_base_seq)) {
1609 stream->ra_base_seq = stream->tmp_ra_base_seq;
1610 ra_base_seq = stream->ra_base_seq;
1611 } else {
1612 ra_base_seq = stream->ra_base_seq;
1613 }
16091614 }
16101615
16111616 /* check if we have enough data to send to L7 */
24452450 * \param stream Reassembled stream returned from the reassembly functions
24462451 */
24472452
2448 static int StreamTcpCheckStreamContents(uint8_t *stream_policy, uint16_t sp_size, TcpStream *stream) {
2453 int StreamTcpCheckStreamContents(uint8_t *stream_policy, uint16_t sp_size, TcpStream *stream) {
24492454 TcpSegment *temp;
24502455 uint16_t i = 0;
24512456 uint8_t j;
58425847 ssn.state = TCP_ESTABLISHED;
58435848
58445849 ssn.server.reassembly_depth = 1048530;
5850 stream_config.reassembly_depth = 0;
58455851
58465852 TcpStream *s = NULL;
58475853 s = &ssn.server;
59005906 return ret;
59015907 }
59025908
5909 /**
5910 * \test Test to make sure we detect the sequence wrap around and continue
5911 * stream reassembly properly.
5912 *
5913 * \retval On success it returns 1 and on failure 0.
5914 */
5915
5916 static int StreamTcpReassembleTest47 (void) {
5917 int ret = 0;
5918 Packet p;
5919 Flow f;
5920 TCPHdr tcph;
5921 Port sp;
5922 Port dp;
5923 Address src;
5924 Address dst;
5925 struct in_addr in;
5926 TcpSession ssn;
5927
5928 memset(&p, 0, sizeof (Packet));
5929 memset(&f, 0, sizeof (Flow));
5930 memset(&tcph, 0, sizeof (TCPHdr));
5931 memset(&src, 0, sizeof(Address));
5932 memset(&dst, 0, sizeof(Address));
5933 memset(&ssn, 0, sizeof(TcpSession));
5934
5935 /* prevent L7 from kicking in */
5936 StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOSERVER, 0);
5937 StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOCLIENT, 0);
5938 StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 0);
5939 StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 0);
5940
5941 FLOW_INITIALIZE(&f);
5942 StreamTcpInitConfig(TRUE);
5943 TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx();
5944 AppLayerDetectProtoThreadInit();
5945
5946 uint8_t httpbuf1[] = "GET /EVILSUFF HTTP/1.1\r\n\r\n";
5947 uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
5948
5949 inet_pton(AF_INET, "1.2.3.4", &in);
5950 src.family = AF_INET;
5951 src.addr_data32[0] = in.s_addr;
5952 inet_pton(AF_INET, "1.2.3.5", &in);
5953 dst.family = AF_INET;
5954 dst.addr_data32[0] = in.s_addr;
5955 sp = 200;
5956 dp = 220;
5957
5958 ssn.server.ra_base_seq = 572799781UL;
5959 ssn.server.isn = 572799781UL;
5960 ssn.server.last_ack = 572799782UL;
5961 ssn.client.ra_base_seq = 4294967289UL;
5962 ssn.client.isn = 4294967289UL;
5963 ssn.client.last_ack = 21;
5964 f.alproto = ALPROTO_UNKNOWN;
5965
5966 f.src = src;
5967 f.dst = dst;
5968 f.sp = sp;
5969 f.dp = dp;
5970 f.protoctx = &ssn;
5971 p.flow = &f;
5972 tcph.th_win = htons(5480);
5973 ssn.state = TCP_ESTABLISHED;
5974 TcpStream *s = NULL;
5975 uint8_t cnt = 0;
5976
5977 for (cnt=0; cnt < httplen1; cnt++) {
5978 tcph.th_seq = htonl(ssn.client.isn + 1 + cnt);
5979 tcph.th_ack = htonl(572799782UL);
5980 tcph.th_flags = TH_ACK|TH_PUSH;
5981 p.tcph = &tcph;
5982 p.flowflags = FLOW_PKT_TOSERVER;
5983 p.payload = &httpbuf1[cnt];
5984 p.payload_len = 1;
5985 s = &ssn.client;
5986
5987 if (StreamTcpReassembleHandleSegment(ra_ctx, &ssn, s, &p) == -1) {
5988 printf("failed in segments reassembly, while processing toserver "
5989 "packet\n");
5990 goto end;
5991 }
5992
5993 p.flowflags = FLOW_PKT_TOCLIENT;
5994 p.payload = NULL;
5995 p.payload_len = 0;
5996 tcph.th_seq = htonl(572799782UL);
5997 tcph.th_ack = htonl(ssn.client.isn + 1 + cnt);
5998 tcph.th_flags = TH_ACK;
5999 p.tcph = &tcph;
6000 s = &ssn.server;
6001
6002 if (StreamTcpReassembleHandleSegment(ra_ctx, &ssn, s, &p) == -1) {
6003 printf("failed in segments reassembly, while processing toserver "
6004 "packet\n");
6005 goto end;
6006 }
6007
6008 /* Process stream smsgs we may have in queue */
6009 if (StreamTcpReassembleProcessAppLayer(ra_ctx) < 0) {
6010 printf("failed in processing stream smsgs\n");
6011 goto end;
6012 }
6013 }
6014
6015 if (f.alproto != ALPROTO_HTTP) {
6016 printf("App layer protocol (HTTP) should have been detected\n");
6017 goto end;
6018 }
6019
6020 ret = 1;
6021 end:
6022 StreamTcpFreeConfig(TRUE);
6023 StreamTcpReassembleFreeThreadCtx(ra_ctx);
6024 return ret;
6025 }
59036026 #endif /* UNITTESTS */
59046027
59056028 /** \brief The Function Register the Unit tests to test the reassembly engine
59546077 UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test", StreamTcpReassembleTest44, 1);
59556078 UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test", StreamTcpReassembleTest45, 1);
59566079 UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test", StreamTcpReassembleTest46, 1);
6080 UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test", StreamTcpReassembleTest47, 1);
59576081 #endif /* UNITTESTS */
59586082 }
7272 void StreamTcpSetOSPolicy(TcpStream *, Packet *);
7373 void StreamTcpReassemblePause (TcpSession *, char );
7474 void StreamTcpReassembleUnPause (TcpSession *, char );
75 int StreamTcpCheckStreamContents(uint8_t *, uint16_t , TcpStream *);
7576
7677 #endif /* __STREAM_TCP_REASSEMBLE_H__ */
7778
2929 #include "decode.h"
3030 #include "debug.h"
3131 #include "detect.h"
32
3233 #include "flow.h"
34 #include "flow-util.h"
35
3336 #include "threads.h"
3437 #include "conf.h"
3538 #include "conf-yaml-loader.h"
97100 static uint64_t ssn_pool_cnt = 0; /** counts ssns, protected by ssn_pool_mutex */
98101 #endif
99102
103 extern uint8_t engine_mode;
104
100105 static SCSpinlock stream_memuse_spinlock;
101106 static uint32_t stream_memuse;
102107 static uint32_t stream_memuse_max;
230235 *
231236 * \param p Packet used to identify the stream.
232237 */
233 static void StreamTcpSessionPktFree (Packet *p)
238 void StreamTcpSessionPktFree (Packet *p)
234239 {
235240 SCEnter();
236241
415420 } else {
416421 stream_config.reassembly_depth = 0;
417422 }
423
424 char *csum = NULL;
425 if ((ConfGet("stream.checksum_validation", &csum)) == 1) {
426 if (strncmp(csum, "yes", 3) == 0) {
427 stream_config.flags |= STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION;
428 }
429 /* Default is that we validate the checksum of all the packets */
430 } else {
431 stream_config.flags |= STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION;
432 }
433
418434 if (!quiet) {
419435 SCLogInfo("stream.reassembly \"depth\": %"PRIu32"", stream_config.reassembly_depth);
420436 }
512528 ssn->state = state;
513529
514530 FlowUpdateQueue(p->flow);
515 }
516
517 /**
518 * \brief Function to flip the direction When we missed the SYN packet,
519 * SYN/ACK is considered as sent by server, but our engine flagged the
520 * packet as from client for the host whose packet is received first in
521 * the session.
522 *
523 * \param ssn TcpSession to whom this packet belongs
524 * \param p Packet whose flag has to be changed
525 */
526 static void StreamTcpPacketSwitchDir(TcpSession *ssn, Packet *p)
527 {
528 SCLogDebug("ssn %p: switching pkt direction", ssn);
529
530 if (PKT_IS_TOSERVER(p)) {
531 p->flowflags &= ~FLOW_PKT_TOSERVER;
532 p->flowflags |= FLOW_PKT_TOCLIENT;
533 } else {
534 p->flowflags &= ~FLOW_PKT_TOCLIENT;
535 p->flowflags |= FLOW_PKT_TOSERVER;
536 }
537531 }
538532
539533 /**
599593 case TH_SYN | TH_CWR | TH_ECN:
600594 case TH_SYN | TH_ECN:
601595 case TH_SYN | TH_CWR:
596 case TH_SYN | TH_PUSH:
597 case TH_SYN | TH_URG:
602598 case TH_SYN:
603599 {
604600 if (ssn == NULL) {
618614 /* set the sequence numbers and window */
619615 ssn->client.isn = TCP_GET_SEQ(p);
620616 ssn->client.ra_base_seq = ssn->client.isn;
617 ssn->client.tmp_ra_base_seq = ssn->client.isn;
621618 ssn->client.next_seq = ssn->client.isn + 1;
622619
623620 /*Set the stream timestamp value, if packet has timestamp option
648645 }
649646 case TH_SYN|TH_ACK:
650647 case TH_SYN|TH_ACK|TH_ECN:
648 case TH_SYN|TH_ACK|TH_ECN|TH_CWR:
651649 if (stream_config.midstream == FALSE &&
652650 stream_config.async_oneside == FALSE)
653651 break;
671669 /* sequence number & window */
672670 ssn->server.isn = TCP_GET_SEQ(p);
673671 ssn->server.ra_base_seq = ssn->server.isn;
672 ssn->server.tmp_ra_base_seq = ssn->server.isn;
674673 ssn->server.next_seq = ssn->server.isn + 1;
675674 ssn->server.window = TCP_GET_WINDOW(p);
676675 SCLogDebug("ssn %p: server window %u", ssn, ssn->server.window);
677676
678677 ssn->client.isn = TCP_GET_ACK(p) - 1;
679678 ssn->client.ra_base_seq = ssn->client.isn;
679 ssn->client.tmp_ra_base_seq = ssn->client.isn;
680680 ssn->client.next_seq = ssn->client.isn + 1;
681681
682682 ssn->client.last_ack = TCP_GET_ACK(p);
723723 /* Handle SYN/ACK and 3WHS shake missed together as it is almost
724724 * similar. */
725725 case TH_ACK:
726 case TH_ACK| TH_URG:
726727 case TH_ACK|TH_ECN:
728 case TH_ACK|TH_ECN|TH_CWR:
727729 case TH_ACK|TH_PUSH:
730 case TH_ACK|TH_PUSH|TH_URG:
728731 case TH_ACK|TH_PUSH|TH_ECN:
732 case TH_ACK|TH_PUSH|TH_ECN|TH_CWR:
729733 if (stream_config.midstream == FALSE)
730734 break;
731735 if (ssn == NULL) {
747751 /* set the sequence numbers and window */
748752 ssn->client.isn = TCP_GET_SEQ(p) - 1;
749753 ssn->client.ra_base_seq = ssn->client.isn;
754 ssn->client.tmp_ra_base_seq = ssn->client.isn;
750755 ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
751756 ssn->client.window = TCP_GET_WINDOW(p);
752757 ssn->client.last_ack = TCP_GET_SEQ(p);
756761
757762 ssn->server.isn = TCP_GET_ACK(p) - 1;
758763 ssn->server.ra_base_seq = ssn->server.isn;
764 ssn->server.tmp_ra_base_seq = ssn->server.isn;
759765 ssn->server.next_seq = ssn->server.isn + 1;
760766 ssn->server.last_ack = TCP_GET_ACK(p);
761767 ssn->server.next_win = ssn->server.last_ack;
800806 case TH_RST:
801807 case TH_RST|TH_ACK:
802808 case TH_RST|TH_ACK|TH_ECN:
809 case TH_RST|TH_ACK|TH_ECN|TH_CWR:
803810 case TH_RST|TH_ACK|TH_PUSH:
804811 case TH_RST|TH_ACK|TH_PUSH|TH_ECN:
812 case TH_RST|TH_ACK|TH_PUSH|TH_ECN|TH_CWR:
805813 case TH_FIN:
806814 case TH_FIN|TH_ACK:
807815 case TH_FIN|TH_ACK|TH_ECN:
816 case TH_FIN|TH_ACK|TH_ECN|TH_CWR:
808817 case TH_FIN|TH_ACK|TH_PUSH:
809818 case TH_FIN|TH_ACK|TH_PUSH|TH_ECN:
819 case TH_FIN|TH_ACK|TH_PUSH|TH_ECN|TH_CWR:
810820 BUG_ON(p->flow->protoctx != NULL);
811821 SCLogDebug("FIN or RST packet received, no session setup");
812822 break;
838848
839849 switch (p->tcph->th_flags) {
840850 case TH_SYN:
851 case TH_SYN|TH_URG:
841852 case TH_SYN|TH_CWR:
842853 case TH_SYN|TH_CWR|TH_ECN:
843854 SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn);
862873 */
863874 ssn->server.isn = TCP_GET_SEQ(p);
864875 ssn->server.ra_base_seq = ssn->server.isn;
876 ssn->server.tmp_ra_base_seq = ssn->server.isn;
865877 ssn->server.next_seq = ssn->server.isn + 1;
866878
867879 /* Set the stream timestamp value, if packet has timestamp
898910 break;
899911 case TH_SYN|TH_ACK:
900912 case TH_SYN|TH_ACK|TH_ECN:
913 case TH_SYN|TH_ACK|TH_ECN|TH_CWR:
901914 if (ssn->flags & STREAMTCP_FLAG_4WHS && PKT_IS_TOSERVER(p)) {
902915 SCLogDebug("ssn %p: SYN/ACK received on 4WHS session", ssn);
903916
927940 /* sequence number & window */
928941 ssn->client.isn = TCP_GET_SEQ(p);
929942 ssn->client.ra_base_seq = ssn->client.isn;
943 ssn->client.tmp_ra_base_seq = ssn->client.isn;
930944 ssn->client.next_seq = ssn->client.isn + 1;
931945
932946 ssn->server.window = TCP_GET_WINDOW(p);
10051019 /* sequence number & window */
10061020 ssn->server.isn = TCP_GET_SEQ(p);
10071021 ssn->server.ra_base_seq = ssn->server.isn;
1022 ssn->server.tmp_ra_base_seq = ssn->server.isn;
10081023 ssn->server.next_seq = ssn->server.isn + 1;
10091024
10101025 ssn->client.window = TCP_GET_WINDOW(p);
10661081 ssn->flags &=~ STREAMTCP_FLAG_4WHS;
10671082 break;
10681083 case TH_ACK:
1084 case TH_ACK|TH_URG:
10691085 case TH_ACK|TH_ECN:
1086 case TH_ACK|TH_ECN|TH_CWR:
10701087 case TH_ACK|TH_PUSH:
1088 case TH_ACK|TH_PUSH|TH_URG:
10711089 case TH_ACK|TH_PUSH|TH_ECN:
1090 case TH_ACK|TH_PUSH|TH_ECN|TH_CWR:
10721091 /* Handle the asynchronous stream, when we receive a SYN packet
10731092 and now istead of receving a SYN/ACK we receive a ACK from the
10741093 same host, which sent the SYN, this suggests the ASNYC streams.*/
10971116 /* Set the server side parameters */
10981117 ssn->server.isn = TCP_GET_ACK(p) - 1;
10991118 ssn->server.ra_base_seq = ssn->server.isn;
1119 ssn->server.tmp_ra_base_seq = ssn->server.isn;
11001120 ssn->server.next_seq = ssn->server.isn + 1;
11011121 ssn->server.last_ack = ssn->server.next_seq;
11021122 ssn->server.next_win = ssn->server.last_ack;
11281148 case TH_RST:
11291149 case TH_RST|TH_ACK:
11301150 case TH_RST|TH_ACK|TH_ECN:
1131 if(ValidReset(ssn, p)){
1132 if(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn) &&
1133 SEQ_EQ(TCP_GET_WINDOW(p), 0) &&
1134 SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1)))
1135 {
1151 case TH_RST|TH_ACK|TH_ECN|TH_CWR:
1152 if (ValidReset(ssn, p)) {
1153 if (PKT_IS_TOSERVER(p)) {
1154 if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn) &&
1155 SEQ_EQ(TCP_GET_WINDOW(p), 0) &&
1156 SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1))) {
1157 StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
1158 SCLogDebug("ssn %p: Reset received and state changed to "
1159 "TCP_CLOSED", ssn);
1160 StreamTcpSessionPktFree(p);
1161 }
1162 } else {
11361163 StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
11371164 SCLogDebug("ssn %p: Reset received and state changed to "
1138 "TCP_CLOSED", ssn);
1165 "TCP_CLOSED", ssn);
11391166 StreamTcpSessionPktFree(p);
11401167 }
11411168 } else
11671194
11681195 switch (p->tcph->th_flags) {
11691196 case TH_SYN:
1197 case TH_SYN|TH_URG:
11701198 case TH_SYN|TH_CWR:
11711199 case TH_SYN|TH_CWR|TH_ECN:
11721200 SCLogDebug("ssn %p: SYN packet on state SYN_RECV... resent", ssn);
11731201 break;
11741202 case TH_SYN|TH_ACK:
11751203 case TH_SYN|TH_ACK|TH_ECN:
1204 case TH_SYN|TH_ACK|TH_ECN|TH_CWR:
11761205 SCLogDebug("ssn %p: SYN/ACK packet on state SYN_RECV. resent", ssn);
11771206 break;
11781207 case TH_ACK:
1208 case TH_ACK|TH_URG:
11791209 case TH_ACK|TH_ECN:
1210 case TH_ACK|TH_ECN|TH_CWR:
11801211 case TH_ACK|TH_PUSH:
1212 case TH_ACK|TH_PUSH|TH_URG:
11811213 case TH_ACK|TH_PUSH|TH_ECN:
1214 case TH_ACK|TH_PUSH|TH_ECN|TH_CWR:
11821215 /* If the timestamp option is enabled for both the streams, then
11831216 * validate the received packet timestamp value against the
11841217 * stream->last_ts. If the timestamp is valid then process the
13281361 case TH_RST:
13291362 case TH_RST|TH_ACK:
13301363 case TH_RST|TH_ACK|TH_ECN:
1364 case TH_RST|TH_ACK|TH_ECN|TH_CWR:
13311365
13321366 if(ValidReset(ssn, p)) {
13331367 uint8_t reset = TRUE;
16291663
16301664 switch (p->tcph->th_flags) {
16311665 case TH_SYN:
1666 case TH_SYN|TH_URG:
16321667 case TH_SYN|TH_CWR:
16331668 case TH_SYN|TH_CWR|TH_ECN:
16341669 SCLogDebug("ssn %p: SYN packet on state ESTABLISED... resent", ssn);
16351670 break;
16361671 case TH_SYN|TH_ACK:
16371672 case TH_SYN|TH_ACK|TH_ECN:
1673 case TH_SYN|TH_ACK|TH_ECN|TH_CWR:
16381674 SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent",
16391675 ssn);
16401676 break;
1677 case TH_ACK|TH_URG:
16411678 case TH_ACK:
16421679 case TH_ACK|TH_ECN:
16431680 case TH_ACK|TH_PUSH:
16441681 case TH_ACK|TH_PUSH|TH_ECN:
1682 case TH_ACK|TH_PUSH|TH_ECN|TH_CWR:
1683 case TH_ACK|TH_PUSH|TH_URG:
1684 /* Urgent pointer size can be more than the payload size, as it tells
1685 the future coming data from the sender will be handled urgently
1686 untill data of size equal to urgent offset has been processed
1687 (RFC 2147)*/
16451688
16461689 /* If the timestamp option is enabled for both the streams, then
16471690 * validate the received packet timestamp value against the
16751718 case TH_FIN:
16761719 case TH_FIN|TH_ACK:
16771720 case TH_FIN|TH_ACK|TH_ECN:
1721 case TH_FIN|TH_ACK|TH_ECN|TH_CWR:
16781722 case TH_FIN|TH_ACK|TH_PUSH:
16791723 case TH_FIN|TH_ACK|TH_PUSH|TH_ECN:
1724 case TH_FIN|TH_ACK|TH_PUSH|TH_ECN|TH_CWR:
16801725
16811726 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
16821727 if (!ValidTimestamp(ssn, p))
16951740 case TH_RST:
16961741 case TH_RST|TH_ACK:
16971742 case TH_RST|TH_ACK|TH_ECN:
1743 case TH_RST|TH_ACK|TH_ECN|TH_CWR:
16981744
16991745 if(ValidReset(ssn, p)) {
17001746 if(PKT_IS_TOSERVER(p)) {
17021748 SCLogDebug("ssn %p: Reset received and state changed to "
17031749 "TCP_CLOSED", ssn);
17041750
1705 ssn->client.next_seq = TCP_GET_ACK(p);
1706 ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1;
1751 ssn->server.next_seq = TCP_GET_ACK(p);
1752 ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
17071753 SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
17081754 ssn->server.next_seq);
17091755 ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
18451891 return -1;
18461892
18471893 switch (p->tcph->th_flags) {
1894 case TH_ACK|TH_URG:
18481895 case TH_ACK:
18491896 case TH_ACK|TH_ECN:
1897 case TH_ACK|TH_ECN|TH_CWR:
18501898
18511899 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
18521900 if (!ValidTimestamp(ssn, p))
19191967 case TH_FIN:
19201968 case TH_FIN|TH_ACK:
19211969 case TH_FIN|TH_ACK|TH_ECN:
1970 case TH_FIN|TH_ACK|TH_ECN|TH_CWR:
19221971 case TH_FIN|TH_ACK|TH_PUSH:
19231972 case TH_FIN|TH_ACK|TH_PUSH|TH_ECN:
1973 case TH_FIN|TH_ACK|TH_PUSH|TH_ECN|TH_CWR:
19241974
19251975 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
19261976 if (!ValidTimestamp(ssn, p))
20022052 case TH_RST:
20032053 case TH_RST|TH_ACK:
20042054 case TH_RST|TH_ACK|TH_ECN:
2055 case TH_RST|TH_ACK|TH_ECN|TH_CWR:
20052056
20062057 if(ValidReset(ssn, p)) {
20072058 StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
20382089 return -1;
20392090
20402091 switch (p->tcph->th_flags) {
2092 case TH_ACK|TH_URG:
20412093 case TH_ACK:
20422094 case TH_ACK|TH_ECN:
2095 case TH_ACK|TH_ECN|TH_CWR:
20432096
20442097 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
20452098 if (!ValidTimestamp(ssn, p))
21132166 case TH_RST:
21142167 case TH_RST|TH_ACK:
21152168 case TH_RST|TH_ACK|TH_ECN:
2169 case TH_RST|TH_ACK|TH_ECN|TH_CWR:
21162170
21172171 if(ValidReset(ssn, p)) {
21182172 StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
22152269 switch(p->tcph->th_flags) {
22162270 case TH_ACK:
22172271 case TH_ACK|TH_ECN:
2272 case TH_ACK|TH_ECN|TH_CWR:
22182273
22192274 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
22202275 if (!ValidTimestamp(ssn, p))
23092364 case TH_FIN:
23102365 case TH_FIN|TH_ACK:
23112366 case TH_FIN|TH_ACK|TH_ECN:
2367 case TH_FIN|TH_ACK|TH_ECN|TH_CWR:
23122368
23132369 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
23142370 if (!ValidTimestamp(ssn, p))
23722428 }
23732429 break;
23742430 case TH_ACK:
2431 case TH_ACK|TH_PUSH:
23752432 case TH_ACK|TH_ECN:
2433 case TH_ACK|TH_ECN|TH_CWR:
23762434 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
23772435 if (!ValidTimestamp(ssn, p))
23782436 SCReturnInt(-1);
23972455 if (SEQ_GT(TCP_GET_ACK(p),ssn->client.last_ack))
23982456 ssn->client.last_ack = TCP_GET_ACK(p);
23992457
2458 if (SEQ_EQ(TCP_GET_SEQ(p),ssn->server.next_seq))
2459 ssn->server.next_seq += p->payload_len;
2460
24002461 StreamTcpReassembleHandleSegment(stt->ra_ctx, ssn,
24012462 &ssn->server, p);
24022463 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
24032464 "%" PRIu32 "", ssn, ssn->server.next_seq,
24042465 ssn->client.last_ack);
24052466 } else {
2406 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
2467 SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
24072468 "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
24082469 TCP_GET_SEQ(p), TCP_GET_ACK(p));
24092470
24212482 if (SEQ_GT(TCP_GET_ACK(p),ssn->server.last_ack))
24222483 ssn->server.last_ack = TCP_GET_ACK(p);
24232484
2485 if (SEQ_EQ(TCP_GET_SEQ(p),ssn->client.next_seq))
2486 ssn->client.next_seq += p->payload_len;
2487
24242488 StreamTcpReassembleHandleSegment(stt->ra_ctx, ssn,
24252489 &ssn->client, p);
24262490 SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
24542518 switch(p->tcph->th_flags) {
24552519 case TH_ACK:
24562520 case TH_ACK|TH_ECN:
2521 case TH_ACK|TH_ECN|TH_CWR:
24572522
24582523 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
24592524 if (!ValidTimestamp(ssn, p))
25152580 switch(p->tcph->th_flags) {
25162581 case TH_ACK:
25172582 case TH_ACK|TH_ECN:
2583 case TH_ACK|TH_ECN|TH_CWR:
25182584
25192585 if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
25202586 if (!ValidTimestamp(ssn, p))
25892655 {
25902656 SCEnter();
25912657 TcpSession *ssn = (TcpSession *)p->flow->protoctx;
2658
2659 /* If we are on IPS mode, and got a drop action triggered from
2660 * the IP only module, or from a reassembled msg and/or from an
2661 * applayer detection, then drop the rest of the packets of the
2662 * same stream and avoid inspecting it any further */
2663 if (StreamTcpCheckFlowDrops(p) == 1) {
2664 SCLogDebug("This flow/stream triggered a drop rule");
2665 FlowSetNoPacketInspectionFlag(p->flow);
2666 DecodeSetNoPacketInspectionFlag(p);
2667 FlowSetSessionNoApplayerInspectionFlag(p->flow);
2668 p->action |= ACTION_DROP;
2669 /* return the segments to the pool */
2670 StreamTcpSessionPktFree(p);
2671 SCReturnInt(0);
2672 }
25922673
25932674 if (ssn == NULL || ssn->state == TCP_NONE) {
25942675 if (StreamTcpPacketStateNone(tv, p, stt, ssn) == -1)
26402721 SCReturnInt(-1);
26412722 break;
26422723 case TCP_CLOSED:
2643 SCLogDebug("packet received on closed state");
2724 /* As our TCP session memory is not returned to pool, until
2725 timeout. If in the mean time we receive any other session from
2726 the same client reusing same port then we switch back to
2727 tcp state none */
2728 if (PKT_IS_TOSERVER(p) && (p->tcph->th_flags & TH_SYN)) {
2729 if(SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
2730 if(StreamTcpPacketStateNone(tv,p,stt,ssn)) {
2731 SCReturnInt(-1);
2732 }
2733 }
2734 } else {
2735 SCLogDebug("packet received on closed state");
2736 }
26442737 break;
26452738 default:
26462739 SCLogDebug("packet received on default state");
26592752 SCReturnInt(0);
26602753 }
26612754
2755 /**
2756 * \brief Function to validate the checksum of the received packet. If the
2757 * checksum is invalid, packet will be dropped, as the end system will
2758 * also drop the packet.
2759 *
2760 * \param p Packet of which checksum has to be validated
2761 * \retval 1 if the checksum is valid, otherwise 0
2762 */
2763 int StreamTcpValidateChecksum(Packet *p)
2764 {
2765 int ret = 1;
2766
2767 if (p->tcpc.comp_csum == -1) {
2768 if (PKT_IS_IPV4(p)) {
2769 p->tcpc.comp_csum = TCPCalculateChecksum((uint16_t *)&(p->ip4h->ip_src),
2770 (uint16_t *)p->tcph,
2771 (p->payload_len +
2772 p->tcpvars.hlen) );
2773 } else if (PKT_IS_IPV6(p)) {
2774 p->tcpc.comp_csum = TCPV6CalculateChecksum((uint16_t *)&(p->ip6h->ip6_src),
2775 (uint16_t *)p->tcph,
2776 (p->payload_len +
2777 p->tcpvars.hlen) );
2778 }
2779 }
2780
2781 if (p->tcpc.comp_csum != p->tcph->th_sum) {
2782 ret = 0;
2783 SCLogDebug("Checksum of recevied packet %p is invalid",p);
2784 }
2785
2786 return ret;
2787 }
2788
26622789 TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq)
26632790 {
26642791 StreamTcpThread *stt = (StreamTcpThread *)data;
26692796
26702797 if (p->flow == NULL)
26712798 return TM_ECODE_OK;
2799
2800 if ((stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION) &&
2801 (StreamTcpValidateChecksum(p) == 0))
2802 {
2803 return TM_ECODE_OK;
2804 }
26722805
26732806 SCMutexLock(&p->flow->m);
26742807 ret = StreamTcpPacket(tv, p, stt);
58035936 return ret;
58045937 }
58055938
5939 #if 0
5940 /**
5941 * \test Test the resetting of the sesison with bad checksum packet and later
5942 * send the malicious contents on the session. Engine should drop the
5943 * packet with the bad checksum.
5944 *
5945 * \retval On success it returns 1 and on failure 0.
5946 */
5947 static int StreamTcpTest29(void)
5948 {
5949 Packet p;
5950 Flow f;
5951 ThreadVars tv;
5952 StreamTcpThread stt;
5953 TCPHdr tcph;
5954 TcpSession ssn;
5955 IPV4Hdr ipv4h;
5956 TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx();
5957 struct in_addr addr;
5958 struct in_addr addr1;
5959 TCPCache tcpc;
5960 TCPVars tcpvars;
5961 TcpStream server;
5962 TcpStream client;
5963
5964 memset (&p, 0, sizeof(Packet));
5965 memset (&f, 0, sizeof(Flow));
5966 memset(&tv, 0, sizeof (ThreadVars));
5967 memset(&stt, 0, sizeof (StreamTcpThread));
5968 memset(&tcph, 0, sizeof (TCPHdr));
5969 memset (&ipv4h, 0, sizeof(IPV4Hdr));
5970 memset (&addr, 0, sizeof(addr));
5971 memset (&addr1, 0, sizeof(addr1));
5972 memset (&tcpc, 0, sizeof(tcpc));
5973 memset (&tcpvars, 0, sizeof(tcpvars));
5974 memset(&ssn, 0, sizeof (TcpSession));
5975 memset(&server, 0, sizeof (TcpStream));
5976 memset(&client, 0, sizeof (TcpStream));
5977 uint8_t packet[1460] = "";
5978 int result = 1;
5979
5980 StreamTcpInitConfig(TRUE);
5981
5982 /* prevent L7 from kicking in */
5983 StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOSERVER, 4096);
5984 StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOCLIENT, 4096);
5985
5986 ssn.client.os_policy = OS_POLICY_BSD;
5987 p.src.family = AF_INET;
5988 p.dst.family = AF_INET;
5989 p.proto = IPPROTO_TCP;
5990 p.flow = &f;
5991 tcph.th_win = 5480;
5992 p.tcph = &tcph;
5993 p.payload = packet;
5994 p.ip4h = &ipv4h;
5995 p.tcpc = tcpc;
5996 p.tcpc.comp_csum = -1;
5997 tcpvars.hlen = 20;
5998 p.tcpvars = tcpvars;
5999 ssn.state = TCP_ESTABLISHED;
6000 addr.s_addr = inet_addr("10.1.3.53");
6001 p.dst.address.address_un_data32[0] = addr.s_addr;
6002 addr1.s_addr = inet_addr("10.1.3.7");
6003 p.src.address.address_un_data32[0] = addr1.s_addr;
6004 f.protoctx = &ssn;
6005 stt.ra_ctx = ra_ctx;
6006 ssn.server = server;
6007 ssn.client = client;
6008 ssn.client.isn = 10;
6009 ssn.client.window = 5184;
6010 ssn.client.last_ack = 10;
6011 ssn.client.ra_base_seq = 10;
6012 ssn.client.next_win = 5184;
6013 ssn.server.isn = 119197101;
6014 ssn.server.window = 5184;
6015 ssn.server.next_win = 5184;
6016 ssn.server.last_ack = 119197101;
6017 ssn.server.ra_base_seq = 119197101;
6018
6019
6020
6021
6022 tcph.th_flags = TH_PUSH | TH_ACK;
6023 p.flowflags = FLOW_PKT_TOSERVER;
6024 p.tcph->th_seq = htonl(11);
6025 p.tcph->th_ack = htonl(119197102);
6026 p.payload_len = 4;
6027 p.ip4h->ip_src = addr1;
6028 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
6029 (uint16_t *)p.tcph,
6030 (p.payload_len +
6031 p.tcpvars.hlen) );
6032
6033 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
6034 printf("failed in segment reassmebling\n");
6035 result &= 0;
6036 goto end;
6037 }
6038
6039 tcph.th_flags = TH_ACK;
6040 p.flowflags = FLOW_PKT_TOCLIENT;
6041 p.tcph->th_seq = htonl(119197102);
6042 p.tcph->th_ack = htonl(15);
6043 p.payload_len = 0;
6044 p.ip4h->ip_src = addr;
6045 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
6046 (uint16_t *)p.tcph,
6047 (p.payload_len +
6048 p.tcpvars.hlen) );
6049
6050 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
6051 printf("failed in segment reassmebling\n");
6052 result &= 0;
6053 goto end;
6054 }
6055
6056 tcph.th_flags = TH_RST | TH_ACK;
6057 p.flowflags = FLOW_PKT_TOSERVER;
6058 p.tcph->th_seq = htonl(15);
6059 p.tcph->th_ack = htonl(119197102);
6060 p.payload_len = 0;
6061 p.ip4h->ip_src = addr1;
6062 p.tcph->th_sum = 12345;
6063
6064 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
6065 printf("failed in segment reassmebling\n");
6066 result &= 0;
6067 goto end;
6068 }
6069
6070 if (ssn.state != TCP_ESTABLISHED) {
6071 printf("the ssn.state should be TCP_ESTABLISHED(%"PRIu8"), not %"PRIu8""
6072 "\n", TCP_ESTABLISHED, ssn.state);
6073 result &= 0;
6074 goto end;
6075 }
6076
6077 end:
6078 StreamTcpReturnStreamSegments(&ssn.client);
6079 StreamTcpFreeConfig(TRUE);
6080 return result;
6081 }
6082
6083 /**
6084 * \test Test the overlapping of the packet with bad checksum packet and later
6085 * send the malicious contents on the session. Engine should drop the
6086 * packet with the bad checksum.
6087 *
6088 * \retval On success it returns 1 and on failure 0.
6089 */
6090 static int StreamTcpTest30(void)
6091 {
6092 Packet p;
6093 Flow f;
6094 ThreadVars tv;
6095 StreamTcpThread stt;
6096 TCPHdr tcph;
6097 TcpSession ssn;
6098 IPV4Hdr ipv4h;
6099 TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx();
6100 struct in_addr addr;
6101 struct in_addr addr1;
6102 TCPCache tcpc;
6103 TCPVars tcpvars;
6104 TcpStream server;
6105 TcpStream client;
6106
6107 memset (&p, 0, sizeof(Packet));
6108 memset (&f, 0, sizeof(Flow));
6109 memset(&tv, 0, sizeof (ThreadVars));
6110 memset(&stt, 0, sizeof (StreamTcpThread));
6111 memset(&tcph, 0, sizeof (TCPHdr));
6112 memset (&ipv4h, 0, sizeof(IPV4Hdr));
6113 memset (&addr, 0, sizeof(addr));
6114 memset (&addr1, 0, sizeof(addr1));
6115 memset (&tcpc, 0, sizeof(tcpc));
6116 memset (&tcpvars, 0, sizeof(tcpvars));
6117 memset(&ssn, 0, sizeof (TcpSession));
6118 memset(&server, 0, sizeof (TcpStream));
6119 memset(&client, 0, sizeof (TcpStream));
6120 uint8_t payload[9] = "AAAAAAAAA";
6121 uint8_t payload1[9] = "GET /EVIL";
6122 uint8_t expected_content[9] = { 0x47, 0x45, 0x54, 0x20, 0x2f, 0x45, 0x56,
6123 0x49, 0x4c };
6124 int result = 1;
6125
6126 StreamTcpInitConfig(TRUE);
6127
6128 /* prevent L7 from kicking in */
6129 StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOSERVER, 4096);
6130 StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOCLIENT, 4096);
6131
6132 ssn.client.os_policy = OS_POLICY_BSD;
6133 p.src.family = AF_INET;
6134 p.dst.family = AF_INET;
6135 p.proto = IPPROTO_TCP;
6136 p.flow = &f;
6137 tcph.th_win = 5480;
6138 p.tcph = &tcph;
6139 p.payload = payload;
6140 p.ip4h = &ipv4h;
6141 p.tcpc = tcpc;
6142 p.tcpc.comp_csum = -1;
6143 p.tcpvars = tcpvars;
6144 ssn.state = TCP_ESTABLISHED;
6145 addr.s_addr = inet_addr("10.1.3.53");
6146 p.dst.address.address_un_data32[0] = addr.s_addr;
6147 addr1.s_addr = inet_addr("10.1.3.7");
6148 p.src.address.address_un_data32[0] = addr1.s_addr;
6149 f.protoctx = &ssn;
6150 stt.ra_ctx = ra_ctx;
6151 ssn.server = server;
6152 ssn.client = client;
6153 ssn.client.isn = 10;
6154 ssn.client.window = 5184;
6155 ssn.client.last_ack = 10;
6156 ssn.client.ra_base_seq = 10;
6157 ssn.client.next_win = 5184;
6158 ssn.server.isn = 1351079940;
6159 ssn.server.window = 5184;
6160 ssn.server.next_win = 1351088132;
6161 ssn.server.last_ack = 1351079940;
6162 ssn.server.ra_base_seq = 1351079940;
6163
6164 tcph.th_flags = TH_PUSH | TH_ACK;
6165 p.flowflags = FLOW_PKT_TOSERVER;
6166 p.tcph->th_seq = htonl(11);
6167 p.tcph->th_ack = htonl(1351079940);
6168 p.payload_len = 9;
6169 p.ip4h->ip_src = addr1;
6170 p.tcph->th_sum = 12345;
6171
6172 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
6173 printf("failed in segment reassmebling\n");
6174 result &= 0;
6175 goto end;
6176 }
6177
6178 tcph.th_flags = TH_PUSH | TH_ACK;
6179 p.flowflags = FLOW_PKT_TOSERVER;
6180 p.tcph->th_seq = htonl(11);
6181 p.tcph->th_ack = htonl(1351079940);
6182 p.payload = payload1;
6183 p.payload_len = 9;
6184 p.ip4h->ip_src = addr1;
6185 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
6186 (uint16_t *)p.tcph,
6187 (p.payload_len +
6188 p.tcpvars.hlen) );
6189
6190 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
6191 printf("failed in segment reassmebling\n");
6192 result &= 0;
6193 goto end;
6194 }
6195
6196 tcph.th_flags = TH_ACK;
6197 p.flowflags = FLOW_PKT_TOCLIENT;
6198 p.tcph->th_seq = htonl(1351079940);
6199 p.tcph->th_ack = htonl(20);
6200 p.payload_len = 0;
6201 p.ip4h->ip_src = addr;
6202 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
6203 (uint16_t *)p.tcph,
6204 (p.payload_len +
6205 p.tcpvars.hlen) );
6206
6207 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
6208 printf("failed in segment reassmebling\n");
6209 result &= 0;
6210 goto end;
6211 }
6212
6213 if (StreamTcpCheckStreamContents(expected_content, 9, &ssn.client) != 1) {
6214 printf("the contents are not as expected(GET /EVIL), contents are: ");
6215 PrintRawDataFp(stdout, ssn.client.seg_list->payload, 9);
6216 result &= 0;
6217 goto end;
6218 }
6219
6220 end:
6221 StreamTcpReturnStreamSegments(&ssn.client);
6222 StreamTcpFreeConfig(TRUE);
6223 return result;
6224 }
6225
6226 /**
6227 * \test Test the multiple SYN packet handling with bad checksum and timestamp
6228 * value. Engine should drop the bad checksum packet and establish
6229 * TCP session correctly.
6230 *
6231 * \retval On success it returns 1 and on failure 0.
6232 */
6233 static int StreamTcpTest31(void)
6234 {
6235 Packet p;
6236 Flow f;
6237 ThreadVars tv;
6238 StreamTcpThread stt;
6239 TCPHdr tcph;
6240 TcpSession ssn;
6241 IPV4Hdr ipv4h;
6242 TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx();
6243 struct in_addr addr;
6244 struct in_addr addr1;
6245 TCPCache tcpc;
6246 TCPVars tcpvars;
6247 TcpStream server;
6248 TcpStream client;
6249 TCPOpt tcpopt;
6250
6251 memset (&p, 0, sizeof(Packet));
6252 memset (&f, 0, sizeof(Flow));
6253 memset(&tv, 0, sizeof (ThreadVars));
6254 memset(&stt, 0, sizeof (StreamTcpThread));
6255 memset(&tcph, 0, sizeof (TCPHdr));
6256 memset (&ipv4h, 0, sizeof(IPV4Hdr));
6257 memset (&addr, 0, sizeof(addr));
6258 memset (&addr1, 0, sizeof(addr1));
6259 memset (&tcpc, 0, sizeof(tcpc));
6260 memset (&tcpvars, 0, sizeof(tcpvars));
6261 memset(&ssn, 0, sizeof (TcpSession));
6262 memset(&server, 0, sizeof (TcpStream));
6263 memset(&client, 0, sizeof (TcpStream));
6264 memset(&tcpopt, 0, sizeof (TCPOpt));
6265 int result = 1;
6266
6267 StreamTcpInitConfig(TRUE);
6268
6269 /* prevent L7 from kicking in */
6270 StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOSERVER, 4096);
6271 StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOCLIENT, 4096);
6272
6273 ssn.client.os_policy = OS_POLICY_LINUX;
6274 p.src.family = AF_INET;
6275 p.dst.family = AF_INET;
6276 p.proto = IPPROTO_TCP;
6277 p.flow = &f;
6278 tcph.th_win = 5480;
6279 p.tcph = &tcph;
6280 p.ip4h = &ipv4h;
6281 p.tcpc = tcpc;
6282 p.tcpc.comp_csum = -1;
6283 p.tcpvars = tcpvars;
6284 p.tcpvars.ts = &tcpopt;
6285 addr.s_addr = inet_addr("10.1.3.53");
6286 p.dst.address.address_un_data32[0] = addr.s_addr;
6287 addr1.s_addr = inet_addr("10.1.3.7");
6288 p.src.address.address_un_data32[0] = addr1.s_addr;
6289 f.protoctx = &ssn;
6290 stt.ra_ctx = ra_ctx;
6291 ssn.server = server;
6292 ssn.client = client;
6293 ssn.client.isn = 10;
6294 ssn.client.window = 5184;
6295 ssn.client.last_ack = 10;
6296 ssn.client.ra_base_seq = 10;
6297 ssn.client.next_win = 5184;
6298 ssn.server.isn = 1351079940;
6299 ssn.server.window = 5184;
6300 ssn.server.next_win = 1351088132;
6301 ssn.server.last_ack = 1351079940;
6302 ssn.server.ra_base_seq = 1351079940;
6303
6304 tcph.th_flags = TH_SYN;
6305 p.flowflags = FLOW_PKT_TOSERVER;
6306 p.tcph->th_seq = htonl(10);
6307 p.payload_len = 0;
6308 p.ip4h->ip_src = addr1;
6309 p.tcpc.ts1 = 100;
6310 p.tcph->th_sum = 12345;
6311
6312 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
6313 printf("failed in segment reassmebling\n");
6314 result &= 0;
6315 goto end;
6316 }
6317
6318 tcph.th_flags = TH_SYN;
6319 p.flowflags = FLOW_PKT_TOSERVER;
6320 p.tcph->th_seq = htonl(10);
6321 p.payload_len = 0;
6322 p.ip4h->ip_src = addr1;
6323 p.tcpc.ts1 = 10;
6324 p.tcpc.comp_csum = -1;
6325 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
6326 (uint16_t *)p.tcph,
6327 (p.payload_len +
6328 p.tcpvars.hlen) );
6329
6330 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
6331 printf("failed in segment reassmebling\n");
6332 result &= 0;
6333 goto end;
6334 }
6335
6336 ssn.flags |= STREAMTCP_FLAG_TIMESTAMP;
6337 tcph.th_flags = TH_SYN | TH_ACK;
6338 p.flowflags = FLOW_PKT_TOCLIENT;
6339 p.tcph->th_seq = htonl(1351079940);
6340 p.tcph->th_ack = htonl(11);
6341 p.payload_len = 0;
6342 p.tcpc.ts1 = 10;
6343 p.ip4h->ip_src = addr;
6344 p.tcpc.comp_csum = -1;
6345 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
6346 (uint16_t *)p.tcph,
6347 (p.payload_len +
6348 p.tcpvars.hlen) );
6349
6350 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
6351 printf("failed in segment reassmebling\n");
6352 result &= 0;
6353 goto end;
6354 }
6355
6356 tcph.th_flags = TH_ACK;
6357 p.flowflags = FLOW_PKT_TOSERVER;
6358 p.tcph->th_seq = htonl(11);
6359 p.tcph->th_ack = htonl(1351079941);
6360 p.payload_len = 0;
6361 p.tcpc.ts1 = 10;
6362 p.ip4h->ip_src = addr1;
6363 p.tcpc.comp_csum = -1;
6364 p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
6365 (uint16_t *)p.tcph,
6366 (p.payload_len +
6367 p.tcpvars.hlen) );
6368
6369 if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
6370 printf("failed in segment reassmebling\n");
6371 result &= 0;
6372 goto end;
6373 }
6374
6375 if (ssn.state != TCP_ESTABLISHED) {
6376 printf("the should have been changed to TCP_ESTABLISHED!!\n ");
6377 result &= 0;
6378 goto end;
6379 }
6380
6381 end:
6382 StreamTcpReturnStreamSegments(&ssn.client);
6383 StreamTcpFreeConfig(TRUE);
6384 return result;
6385 }
6386
6387 /**
6388 * \test Test the initialization of tcp streams with ECN & CWR flags
6389 *
6390 * \retval On success it returns 1 and on failure 0.
6391 */
6392 static int StreamTcpTest32(void) {
6393 Packet p;
6394 Flow f;
6395 ThreadVars tv;
6396 StreamTcpThread stt;
6397 uint8_t payload[4];
6398 TCPHdr tcph;
6399 TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx();
6400 int ret = 0;
6401
6402 memset (&p, 0, sizeof(Packet));
6403 memset (&f, 0, sizeof(Flow));
6404 memset(&tv, 0, sizeof (ThreadVars));
6405 memset(&stt, 0, sizeof (StreamTcpThread));
6406 memset(&tcph, 0, sizeof (TCPHdr));
6407
6408 stt.ra_ctx = ra_ctx;
6409 p.flow = &f;
6410 tcph.th_win = htons(5480);
6411 tcph.th_flags = TH_SYN | TH_CWR | TH_ECN;
6412 p.tcph = &tcph;
6413 p.flowflags = FLOW_PKT_TOSERVER;
6414
6415 StreamTcpInitConfig(TRUE);
6416
6417 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6418 goto end;
6419
6420 p.tcph->th_ack = htonl(1);
6421 p.tcph->th_flags = TH_SYN | TH_ACK | TH_ECN;
6422 p.flowflags = FLOW_PKT_TOCLIENT;
6423
6424 if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
6425 printf("failed in processing packet\n");
6426 goto end;
6427 }
6428
6429 p.tcph->th_ack = htonl(1);
6430 p.tcph->th_seq = htonl(1);
6431 p.tcph->th_flags = TH_ACK | TH_ECN | TH_CWR;
6432 p.flowflags = FLOW_PKT_TOSERVER;
6433
6434 if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
6435 printf("failed in processing packet\n");
6436 goto end;
6437 }
6438
6439 p.tcph->th_ack = htonl(1);
6440 p.tcph->th_seq = htonl(2);
6441 p.tcph->th_flags = TH_PUSH | TH_ACK | TH_ECN | TH_CWR;
6442 p.flowflags = FLOW_PKT_TOSERVER;
6443
6444 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
6445 p.payload = payload;
6446 p.payload_len = 3;
6447
6448 if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
6449 printf("failed in processing packet\n");
6450 goto end;
6451 }
6452
6453 p.flowflags = FLOW_PKT_TOCLIENT;
6454 p.tcph->th_flags = TH_ACK;
6455 if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
6456 printf("failed in processing packet\n");
6457 goto end;
6458 }
6459
6460 if (((TcpSession *)p.flow->protoctx)->state != TCP_ESTABLISHED) {
6461 printf("the TCP state should be TCP_ESTABLISEHD\n");
6462 goto end;
6463 }
6464 StreamTcpSessionClear(p.flow->protoctx);
6465
6466 ret = 1;
6467 end:
6468 StreamTcpFreeConfig(TRUE);
6469 return ret;
6470 }
6471
6472 /**
6473 * \test Test the allocation of TCP session for a given packet when the same
6474 * ports have been used to start the new session after resetting the
6475 * previous session.
6476 *
6477 * \retval On success it returns 1 and on failure 0.
6478 */
6479
6480 static int StreamTcpTest33 (void) {
6481 Packet p;
6482 Flow f;
6483 ThreadVars tv;
6484 StreamTcpThread stt;
6485 TCPHdr tcph;
6486 TcpReassemblyThreadCtx ra_ctx;
6487 StreamMsgQueue stream_q;
6488 memset(&stream_q, 0, sizeof(StreamMsgQueue));
6489 memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx));
6490 memset (&p, 0, sizeof(Packet));
6491 memset (&f, 0, sizeof(Flow));
6492 memset(&tv, 0, sizeof (ThreadVars));
6493 memset(&stt, 0, sizeof (StreamTcpThread));
6494 memset(&tcph, 0, sizeof (TCPHdr));
6495 p.flow = &f;
6496 tcph.th_win = htons(5480);
6497 tcph.th_flags = TH_SYN;
6498 p.tcph = &tcph;
6499 p.flowflags = FLOW_PKT_TOSERVER;
6500 int ret = 0;
6501 ra_ctx.stream_q = &stream_q;
6502 stt.ra_ctx = &ra_ctx;
6503
6504 StreamTcpInitConfig(TRUE);
6505
6506 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6507 goto end;
6508
6509 p.tcph->th_ack = htonl(1);
6510 p.tcph->th_flags = TH_SYN | TH_ACK;
6511 p.flowflags = FLOW_PKT_TOCLIENT;
6512
6513 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6514 goto end;
6515
6516 p.tcph->th_ack = htonl(1);
6517 p.tcph->th_seq = htonl(1);
6518 p.tcph->th_flags = TH_ACK;
6519 p.flowflags = FLOW_PKT_TOSERVER;
6520
6521 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6522 goto end;
6523
6524 p.tcph->th_ack = htonl(1);
6525 p.tcph->th_seq = htonl(1);
6526 p.tcph->th_flags = TH_RST | TH_ACK;
6527 p.flowflags = FLOW_PKT_TOSERVER;
6528
6529 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6530 goto end;
6531
6532 if (((TcpSession *)(p.flow->protoctx))->state != TCP_CLOSED) {
6533 printf("Tcp session should have been closed\n");
6534 goto end;
6535 }
6536
6537 p.tcph->th_seq = htonl(1);
6538 p.tcph->th_flags = TH_SYN;
6539 p.flowflags = FLOW_PKT_TOSERVER;
6540
6541 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6542 goto end;
6543
6544 p.tcph->th_seq = htonl(1);
6545 p.tcph->th_ack = htonl(2);
6546 p.tcph->th_flags = TH_SYN | TH_ACK;
6547 p.flowflags = FLOW_PKT_TOCLIENT;
6548
6549 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6550 goto end;
6551
6552 p.tcph->th_ack = htonl(2);
6553 p.tcph->th_seq = htonl(2);
6554 p.tcph->th_flags = TH_ACK;
6555 p.flowflags = FLOW_PKT_TOSERVER;
6556
6557 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6558 goto end;
6559
6560 if (((TcpSession *)(p.flow->protoctx))->state != TCP_ESTABLISHED) {
6561 printf("Tcp session should have been ESTABLISHED\n");
6562 goto end;
6563 }
6564
6565 ret = 1;
6566 end:
6567 StreamTcpSessionClear(p.flow->protoctx);
6568 StreamTcpFreeConfig(TRUE);
6569 return ret;
6570 }
6571
6572 /**
6573 * \test Test the allocation of TCP session for a given packet when the SYN
6574 * packet is sent with the PUSH flag set.
6575 *
6576 * \retval On success it returns 1 and on failure 0.
6577 */
6578
6579 static int StreamTcpTest34 (void) {
6580 Packet p;
6581 Flow f;
6582 ThreadVars tv;
6583 StreamTcpThread stt;
6584 TCPHdr tcph;
6585 TcpReassemblyThreadCtx ra_ctx;
6586 StreamMsgQueue stream_q;
6587 memset(&stream_q, 0, sizeof(StreamMsgQueue));
6588 memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx));
6589 memset (&p, 0, sizeof(Packet));
6590 memset (&f, 0, sizeof(Flow));
6591 memset(&tv, 0, sizeof (ThreadVars));
6592 memset(&stt, 0, sizeof (StreamTcpThread));
6593 memset(&tcph, 0, sizeof (TCPHdr));
6594 p.flow = &f;
6595 tcph.th_win = htons(5480);
6596 tcph.th_flags = TH_SYN|TH_PUSH;
6597 p.tcph = &tcph;
6598 p.flowflags = FLOW_PKT_TOSERVER;
6599 int ret = 0;
6600 ra_ctx.stream_q = &stream_q;
6601 stt.ra_ctx = &ra_ctx;
6602
6603 StreamTcpInitConfig(TRUE);
6604
6605 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6606 goto end;
6607
6608 p.tcph->th_ack = htonl(1);
6609 p.tcph->th_flags = TH_SYN | TH_ACK;
6610 p.flowflags = FLOW_PKT_TOCLIENT;
6611
6612 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6613 goto end;
6614
6615 p.tcph->th_ack = htonl(1);
6616 p.tcph->th_seq = htonl(1);
6617 p.tcph->th_flags = TH_ACK;
6618 p.flowflags = FLOW_PKT_TOSERVER;
6619
6620 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6621 goto end;
6622
6623 if (((TcpSession *)(p.flow->protoctx))->state != TCP_ESTABLISHED) {
6624 printf("Tcp session should have been establisehd\n");
6625 goto end;
6626 }
6627
6628 ret = 1;
6629 end:
6630 StreamTcpSessionClear(p.flow->protoctx);
6631 StreamTcpFreeConfig(TRUE);
6632 return ret;
6633 }
6634
6635 /**
6636 * \test Test the allocation of TCP session for a given packet when the SYN
6637 * packet is sent with the URG flag set.
6638 *
6639 * \retval On success it returns 1 and on failure 0.
6640 */
6641
6642 static int StreamTcpTest35 (void) {
6643 Packet p;
6644 Flow f;
6645 ThreadVars tv;
6646 StreamTcpThread stt;
6647 TCPHdr tcph;
6648 TcpReassemblyThreadCtx ra_ctx;
6649 StreamMsgQueue stream_q;
6650 memset(&stream_q, 0, sizeof(StreamMsgQueue));
6651 memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx));
6652 memset (&p, 0, sizeof(Packet));
6653 memset (&f, 0, sizeof(Flow));
6654 memset(&tv, 0, sizeof (ThreadVars));
6655 memset(&stt, 0, sizeof (StreamTcpThread));
6656 memset(&tcph, 0, sizeof (TCPHdr));
6657 p.flow = &f;
6658 tcph.th_win = htons(5480);
6659 tcph.th_flags = TH_SYN|TH_URG;
6660 p.tcph = &tcph;
6661 p.flowflags = FLOW_PKT_TOSERVER;
6662 int ret = 0;
6663 ra_ctx.stream_q = &stream_q;
6664 stt.ra_ctx = &ra_ctx;
6665
6666 StreamTcpInitConfig(TRUE);
6667
6668 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6669 goto end;
6670
6671 p.tcph->th_ack = htonl(1);
6672 p.tcph->th_flags = TH_SYN | TH_ACK;
6673 p.flowflags = FLOW_PKT_TOCLIENT;
6674
6675 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6676 goto end;
6677
6678 p.tcph->th_ack = htonl(1);
6679 p.tcph->th_seq = htonl(1);
6680 p.tcph->th_flags = TH_ACK;
6681 p.flowflags = FLOW_PKT_TOSERVER;
6682
6683 if (StreamTcpPacket(&tv, &p, &stt) == -1)
6684 goto end;
6685
6686 if (((TcpSession *)(p.flow->protoctx))->state != TCP_ESTABLISHED) {
6687 printf("Tcp session should have been establisehd\n");
6688 goto end;
6689 }
6690
6691 ret = 1;
6692 end:
6693 StreamTcpSessionClear(p.flow->protoctx);
6694 StreamTcpFreeConfig(TRUE);
6695 return ret;
6696 }
6697
6698 /**
6699 * \test Test the processing of PSH and URG flag in tcp session.
6700 *
6701 * \retval On success it returns 1 and on failure 0.
6702 */
6703 static int StreamTcpTest36(void) {
6704 Packet p;
6705 Flow f;
6706 ThreadVars tv;
6707 StreamTcpThread stt;
6708 uint8_t payload[4];
6709 TCPHdr tcph;
6710 TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx();
6711 int ret = 0;
6712
6713 memset (&p, 0, sizeof(Packet));
6714 memset (&f, 0, sizeof(Flow));
6715 memset(&tv, 0, sizeof (ThreadVars));
6716 memset(&stt, 0, sizeof (StreamTcpThread));
6717 memset(&tcph, 0, sizeof (TCPHdr));
6718
6719 stt.ra_ctx = ra_ctx;
6720 p.flow = &f;
6721 tcph.th_win = htons(5480);
6722 tcph.th_flags = TH_SYN;
6723 p.tcph = &tcph;
6724 p.flowflags = FLOW_PKT_TOSERVER;
6725
6726 StreamTcpInitConfig(TRUE);
6727
6728 if (StreamTcpPacket(&tv, &p, &stt) == -1) {
6729 printf("failed in processing packet\n");
6730 goto end;
6731 }
6732
6733 p.tcph->th_ack = htonl(1);
6734 p.tcph->th_flags = TH_SYN | TH_ACK;
6735 p.flowflags = FLOW_PKT_TOCLIENT;
6736
6737 if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
6738 printf("failed in processing packet\n");
6739 goto end;
6740 }
6741
6742 p.tcph->th_ack = htonl(1);
6743 p.tcph->th_seq = htonl(1);
6744 p.tcph->th_flags = TH_ACK;
6745 p.flowflags = FLOW_PKT_TOSERVER;
6746
6747 if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
6748 printf("failed in processing packet\n");
6749 goto end;
6750 }
6751
6752 if (((TcpSession *)p.flow->protoctx)->state != TCP_ESTABLISHED) {
6753 printf("the TCP state should be TCP_ESTABLISEHD\n");
6754 goto end;
6755 }
6756
6757 p.tcph->th_ack = htonl(2);
6758 p.tcph->th_seq = htonl(1);
6759 p.tcph->th_flags = TH_PUSH | TH_ACK | TH_URG;
6760 p.flowflags = FLOW_PKT_TOSERVER;
6761
6762 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
6763 p.payload = payload;
6764 p.payload_len = 3;
6765
6766 if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
6767 printf("failed in processing packet\n");
6768 goto end;
6769 }
6770
6771 if (((TcpSession *)p.flow->protoctx)->client.next_seq != 4) {
6772 printf("the ssn->client.next_seq should be 4, but it is %"PRIu32"\n",
6773 ((TcpSession *)p.flow->protoctx)->client.next_seq);
6774 goto end;
6775 }
6776
6777 StreamTcpSessionClear(p.flow->protoctx);
6778
6779 ret = 1;
6780 end:
6781 StreamTcpFreeConfig(TRUE);
6782 return ret;
6783 }
6784 #endif
6785
6786 /**
6787 * \test Test the processing of out of order FIN packets in tcp session.
6788 *
6789 * \retval On success it returns 1 and on failure 0.
6790 */
6791 static int StreamTcpTest37(void) {
6792 Packet p;
6793 Flow f;
6794 ThreadVars tv;
6795 StreamTcpThread stt;
6796 uint8_t payload[4];
6797 TCPHdr tcph;
6798 TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx();
6799 int ret = 0;
6800
6801 memset (&p, 0, sizeof(Packet));
6802 memset (&f, 0, sizeof(Flow));
6803 memset(&tv, 0, sizeof (ThreadVars));
6804 memset(&stt, 0, sizeof (StreamTcpThread));
6805 memset(&tcph, 0, sizeof (TCPHdr));
6806
6807 FLOW_INITIALIZE(&f);
6808
6809 stt.ra_ctx = ra_ctx;
6810 p.flow = &f;
6811 tcph.th_win = htons(5480);
6812 tcph.th_flags = TH_SYN;
6813 p.tcph = &tcph;
6814 p.flowflags = FLOW_PKT_TOSERVER;
6815
6816 StreamTcpInitConfig(TRUE);
6817
6818 if (StreamTcpPacket(&tv, &p, &stt) == -1) {
6819 printf("failed in processing packet\n");
6820 goto end;
6821 }
6822
6823 p.tcph->th_ack = htonl(1);
6824 p.tcph->th_flags = TH_SYN | TH_ACK;
6825 p.flowflags = FLOW_PKT_TOCLIENT;
6826
6827 if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
6828 printf("failed in processing packet\n");
6829 goto end;
6830 }
6831
6832 p.tcph->th_ack = htonl(1);
6833 p.tcph->th_seq = htonl(1);
6834 p.tcph->th_flags = TH_ACK;
6835 p.flowflags = FLOW_PKT_TOSERVER;
6836
6837 if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
6838 printf("failed in processing packet\n");
6839 goto end;
6840 }
6841
6842 if (((TcpSession *)p.flow->protoctx)->state != TCP_ESTABLISHED) {
6843 printf("the TCP state should be TCP_ESTABLISEHD\n");
6844 goto end;
6845 }
6846
6847 p.tcph->th_ack = htonl(2);
6848 p.tcph->th_seq = htonl(4);
6849 p.tcph->th_flags = TH_ACK|TH_FIN;
6850 p.flowflags = FLOW_PKT_TOSERVER;
6851
6852 if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
6853 printf("failed in processing packet\n");
6854 goto end;
6855 }
6856
6857 if (((TcpSession *)p.flow->protoctx)->state != TCP_CLOSE_WAIT) {
6858 printf("the TCP state should be TCP_CLOSE_WAIT\n");
6859 goto end;
6860 }
6861
6862 p.tcph->th_ack = htonl(1);
6863 p.tcph->th_seq = htonl(1);
6864 p.tcph->th_flags = TH_PUSH | TH_ACK;
6865 p.flowflags = FLOW_PKT_TOSERVER;
6866
6867 StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
6868 p.payload = payload;
6869 p.payload_len = 3;
6870
6871 if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
6872 printf("failed in processing packet\n");
6873 goto end;
6874 }
6875
6876 p.tcph->th_ack = htonl(4);
6877 p.tcph->th_seq = htonl(2);
6878 p.tcph->th_flags = TH_ACK;
6879 p.payload_len = 0;
6880 p.flowflags = FLOW_PKT_TOCLIENT;
6881
6882 if (StreamTcpPacket(&tv, &p, &stt) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
6883 printf("failed in processing packet\n");
6884 goto end;
6885 }
6886
6887 if (((TcpSession *)p.flow->protoctx)->client.tmp_ra_base_seq != 3) {
6888 printf("the ssn->client.next_seq should be 3, but it is %"PRIu32"\n",
6889 ((TcpSession *)p.flow->protoctx)->client.tmp_ra_base_seq);
6890 goto end;
6891 }
6892
6893 StreamTcpSessionClear(p.flow->protoctx);
6894
6895 ret = 1;
6896 end:
6897 StreamTcpFreeConfig(TRUE);
6898 return ret;
6899 }
58066900 #endif /* UNITTESTS */
58076901
58086902 void StreamTcpRegisterTests (void) {
58546948 UtRegisterTest("StreamTcpTest27 -- test ecn/cwr sessions",
58556949 StreamTcpTest27, 1);
58566950 UtRegisterTest("StreamTcpTest28 -- Memcap Test", StreamTcpTest28, 1);
6951 #if 0 /* VJ 2010/09/01 disabled since they blow up on Fedora and Fedora is
6952 * right about blowing up. The checksum functions are not used properly
6953 * in the tests. */
6954 UtRegisterTest("StreamTcpTest29 -- Badchecksum Reset Test", StreamTcpTest29, 1);
6955 UtRegisterTest("StreamTcpTest30 -- Badchecksum Overlap Test", StreamTcpTest30, 1);
6956 UtRegisterTest("StreamTcpTest31 -- MultipleSyns Test", StreamTcpTest31, 1);
6957 UtRegisterTest("StreamTcpTest32 -- Bogus CWR Test", StreamTcpTest32, 1);
6958 UtRegisterTest("StreamTcpTest33 -- RST-SYN Again Test", StreamTcpTest33, 1);
6959 UtRegisterTest("StreamTcpTest34 -- SYN-PUSH Test", StreamTcpTest34, 1);
6960 UtRegisterTest("StreamTcpTest35 -- SYN-URG Test", StreamTcpTest35, 1);
6961 UtRegisterTest("StreamTcpTest36 -- PUSH-URG Test", StreamTcpTest36, 1);
6962 #endif
6963 UtRegisterTest("StreamTcpTest37 -- Out of order FIN Test", StreamTcpTest37, 1);
58576964
58586965 /* set up the reassembly tests as well */
58596966 StreamTcpReassembleRegisterTests();
3434 #include "stream-tcp-reassemble.h"
3535
3636 #define STREAM_VERBOSE FALSE
37 /* Flag to indicate that the checksum validation for the stream engine
38 has been enabled */
39 #define STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION 0x01
40
3741 /*global flow data*/
3842 typedef struct TcpStreamCnf_ {
3943 uint32_t memcap; /** max stream mem usage */
4347 int async_oneside;
4448 uint32_t reassembly_memcap; /**< max memory usage for stream reassembly */
4549 uint32_t reassembly_depth; /**< Depth until when we reassemble the stream */
50 uint8_t flags;
4651 } TcpStreamCnf;
4752
4853 TcpStreamCnf stream_config;
5156 void StreamTcpFreeConfig(char);
5257 void StreamTcpRegisterTests (void);
5358
59 void StreamTcpSessionPktFree (Packet *);
60
5461 void StreamTcpIncrMemuse(uint32_t);
5562 void StreamTcpDecrMemuse(uint32_t);
5663 int StreamTcpCheckMemcap(uint32_t);
5764
65
66 /** ------- Inline functions: ------ */
67
68 /**
69 * \brief If we are on IPS mode, and got a drop action triggered from
70 * the IP only module, or from a reassembled msg and/or from an
71 * applayer detection, then drop the rest of the packets of the
72 * same stream and avoid inspecting it any further
73 * \param p pointer to the Packet to check
74 * \retval 1 if we must drop this stream
75 * \retval 0 if the stream still legal
76 */
77 static inline int StreamTcpCheckFlowDrops(Packet *p) {
78 extern uint8_t engine_mode;
79 /* If we are on IPS mode, and got a drop action triggered from
80 * the IP only module, or from a reassembled msg and/or from an
81 * applayer detection, then drop the rest of the packets of the
82 * same stream and avoid inspecting it any further */
83 if (IS_ENGINE_MODE_IPS(engine_mode) && (p->flow->flags & FLOW_ACTION_DROP))
84 return 1;
85
86 return 0;
87 }
88
89 /**
90 * \brief Function to flip the direction When we missed the SYN packet,
91 * SYN/ACK is considered as sent by server, but our engine flagged the
92 * packet as from client for the host whose packet is received first in
93 * the session.
94 *
95 * \param ssn TcpSession to whom this packet belongs
96 * \param p Packet whose flag has to be changed
97 */
98 static inline void StreamTcpPacketSwitchDir(TcpSession *ssn, Packet *p)
99 {
100 SCLogDebug("ssn %p: switching pkt direction", ssn);
101
102 if (PKT_IS_TOSERVER(p)) {
103 p->flowflags &= ~FLOW_PKT_TOSERVER;
104 p->flowflags |= FLOW_PKT_TOCLIENT;
105 } else {
106 p->flowflags &= ~FLOW_PKT_TOCLIENT;
107 p->flowflags |= FLOW_PKT_TOSERVER;
108 }
109 }
110
111
58112 #endif /* __STREAM_TCP_H__ */
59113
3333 #include "threads.h"
3434 #include "threadvars.h"
3535
36 #include "util-atomic.h"
3637 #include "util-spm.h"
3738 #include "util-hash.h"
3839 #include "util-hashlist.h"
105106 #include "app-layer-htp.h"
106107 #include "app-layer-ftp.h"
107108 #include "app-layer-ssl.h"
109 #include "app-layer-ssh.h"
108110
109111 #include "util-radix-tree.h"
110112 #include "util-host-os-info.h"
140142 #include "tmqh-packetpool.h"
141143
142144 #include "util-ringbuffer.h"
145 #include "util-mem.h"
143146
144147 /*
145148 * we put this here, because we only use it here in main.
148151 volatile sig_atomic_t sighup_count = 0;
149152 volatile sig_atomic_t sigterm_count = 0;
150153
154 /*
155 * Flag to indicate if the engine is at the initialization
156 * or already processing packets. 2 stages: SURICATA_INIT,
157 * SURICATA_RUNTIME and SURICATA_FINALIZE
158 */
159 SC_ATOMIC_DECLARE(unsigned int, engine_stage);
160
151161 /* Max packets processed simultaniously. */
152162 #define DEFAULT_MAX_PENDING_PACKETS 50
153163
156166
157167 /** Run mode selected */
158168 int run_mode = MODE_UNKNOWN;
169
170 /** Engine mode: inline (ENGINE_MODE_IPS) or just
171 * detection mode (ENGINE_MODE_IDS by default) */
172 uint8_t engine_mode = ENGINE_MODE_IDS;
159173
160174 /** Maximum packets to simultaneously process. */
161175 intmax_t max_pending_packets;
370384
371385 sc_set_caps = FALSE;
372386
387 SC_ATOMIC_INIT(engine_stage);
388
373389 /* initialize the logging subsys */
374390 SCLogInitLogModule(NULL);
391
392 /* By default use IDS mode, but if nfq or ipfw
393 * are specified, IPS mode will overwrite this */
394 SET_ENGINE_MODE_IDS(engine_mode);
375395
376396 #ifdef OS_WIN32
377397 /* service initialization */
614634 #ifdef NFQ
615635 if (run_mode == MODE_UNKNOWN) {
616636 run_mode = MODE_NFQ;
637 SET_ENGINE_MODE_IPS(engine_mode);
617638 } else {
618639 SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode "
619640 "has been specified");
630651 #ifdef IPFW
631652 if (run_mode == MODE_UNKNOWN) {
632653 run_mode = MODE_IPFW;
654 SET_ENGINE_MODE_IPS(engine_mode);
633655 } else {
634656 SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode "
635657 "has been specified");
827849 RegisterDCERPCUDPParsers();
828850 RegisterFTPParsers();
829851 RegisterSSLParsers();
852 RegisterSSHParsers();
830853 AppLayerParsersInitPostProcess();
831854
832855 #ifdef UNITTESTS
863886 DecodeVLANRegisterTests();
864887 HTPParserRegisterTests();
865888 TLSParserRegisterTests();
889 SSHParserRegisterTests();
866890 SMBParserRegisterTests();
867891 DCERPCParserRegisterTests();
868892 DCERPCUDPParserRegisterTests();
11041128 exit(EXIT_FAILURE);
11051129 }
11061130
1131 SC_ATOMIC_CAS(&engine_stage, SURICATA_INIT, SURICATA_RUNTIME);
1132
11071133 /* Un-pause all the paused threads */
11081134 TmThreadContinueThreads();
11091135
11611187
11621188 usleep(100);
11631189 }
1190
1191 /* Update the engine stage/status flag */
1192 SC_ATOMIC_CAS(&engine_stage, SURICATA_RUNTIME, SURICATA_DEINIT);
11641193
11651194
11661195 FlowShutdown();
12311260 return 0;
12321261 }
12331262 #endif /* OS_WIN32 */
1263
1264 SC_ATOMIC_DESTROY(engine_stage);
12341265 exit(EXIT_SUCCESS);
12351266 }
2929
3030 /* the name of our binary */
3131 #define PROG_NAME "Suricata"
32 #define PROG_VER "1.0.1"
32 #define PROG_VER "1.0.2"
3333
3434 /* runtime engine control flags */
3535 #define SURICATA_STOP 0x01 /**< gracefully stop the engine: process all
4949 MODE_ERF_FILE,
5050 MODE_DAG,
5151 };
52
53 /* Engine stage/status*/
54 enum {
55 SURICATA_INIT = 0,
56 SURICATA_RUNTIME,
57 SURICATA_DEINIT
58 };
59
60 /* Engine is acting as */
61 enum {
62 ENGINE_MODE_IDS,
63 ENGINE_MODE_IPS,
64 };
65
66 /** You can use this macros to set/check if we have real drop capabilities */
67 #define SET_ENGINE_MODE_IPS(engine_mode) (engine_mode = ENGINE_MODE_IPS);
68 #define SET_ENGINE_MODE_IDS(engine_mode) (engine_mode = ENGINE_MODE_IDS);
69 #define IS_ENGINE_MODE_IPS(engine_mode) (engine_mode == ENGINE_MODE_IPS)
70 #define IS_ENGINE_MODE_IDS(engine_mode) (engine_mode == ENGINE_MODE_IDS)
5271
5372 /* queue's between various other threads
5473 * XXX move to the TmQueue structure later
4343 #include "tmqh-packetpool.h"
4444
4545 #include "util-ringbuffer.h"
46 #include "util-debug.h"
47 #include "util-error.h"
4648
4749 static RingBuffer16 *ringbuffer = NULL;
48
50 /**
51 * \brief TmqhPacketpoolRegister
52 * \initonly
53 */
4954 void TmqhPacketpoolRegister (void) {
5055 tmqh_table[TMQH_PACKETPOOL].name = "packetpool";
5156 tmqh_table[TMQH_PACKETPOOL].InHandler = TmqhInputPacketpool;
5257 tmqh_table[TMQH_PACKETPOOL].OutHandler = TmqhOutputPacketpool;
5358
5459 ringbuffer = RingBufferInit();
60 if (ringbuffer == NULL) {
61 SCLogError(SC_ERR_FATAL, "Error registering Packet pool handler (at ring buffer init)");
62 exit(EXIT_FAILURE);
63 }
5564 }
5665
5766 int PacketPoolIsEmpty(void) {
4242 void TmqhOutputRingBufferSrMw(ThreadVars *t, Packet *p);
4343 void TmqhInputRingBufferShutdownHandler(ThreadVars *);
4444
45 /**
46 * \brief TmqhRingBufferRegister
47 * \initonly
48 */
4549 void TmqhRingBufferRegister (void) {
4650 tmqh_table[TMQH_RINGBUFFER_MRSW].name = "ringbuffer_mrsw";
4751 tmqh_table[TMQH_RINGBUFFER_MRSW].InHandler = TmqhInputRingBufferMrSw;
6367 int i = 0;
6468 for (i = 0; i < 256; i++) {
6569 ringbuffers[i] = RingBuffer8Init();
70 if (ringbuffers[i] == NULL) {
71 SCLogError(SC_ERR_FATAL, "Error allocating memory to register Ringbuffers. Exiting...");
72 exit(EXIT_FAILURE);
73 }
6674 }
6775 }
6876
5151 #define SC_ATOMIC_DECLARE(type, name) \
5252 type name ## _sc_atomic__; \
5353 SCSpinlock name ## _sc_lock__
54
55 /**
56 * \brief wrapper to reference an atomic variable already declared on another file (including the spin lock)
57 *
58 */
59 #define SC_ATOMIC_EXTERN(type, name) \
60 extern type name ## _sc_atomic__; \
61 extern SCSpinlock name ## _sc_lock__
5462
5563 /**
5664 * \brief wrapper to declare an atomic variable including a (spin) lock
199207 type name ## _sc_atomic__
200208
201209 /**
210 * \brief wrapper for referencing an atomic variable declared on another file.
211 *
212 * \warning Only char, short, int, long, long long and their unsigned
213 * versions are supported.
214 *
215 * \param type Type of the variable (char, short, int, long, long long)
216 * \param name Name of the variable.
217 *
218 * We just declare the variable here as we rely on atomic operations
219 * to modify it, so no need for locks.
220 *
221 */
222 #define SC_ATOMIC_EXTERN(type, name) \
223 extern type name ## _sc_atomic__
224
225 /**
202226 * \brief wrapper for declaring an atomic variable and initializing it.
203227 **/
204228 #define SC_ATOMIC_DECL_AND_INIT(type, name) \
523523 * \brief Returns a new output_interface_context
524524 *
525525 * \retval iface_ctx Pointer to a newly allocated output_interface_context
526 * \initonly
526527 */
527528 static inline SCLogOPIfaceCtx *SCLogAllocLogOPIfaceCtx()
528529 {
546547 * \param log_level Override of the global_log_level by this interface
547548 *
548549 * \retval iface_ctx Pointer to the file output interface context created
550 * \initonly
549551 */
550552 static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file,
551553 const char *log_format,
606608 * \param log_level Override of the global_log_level by this interface
607609 *
608610 * \retval iface_ctx Pointer to the console output interface context created
611 * \initonly
609612 */
610613 static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format,
611614 SCLogLevel log_level)
933936 * conf file
934937 *
935938 * \retval sc_lid Pointer to the newly created SCLogInitData
939 * \initonly
936940 */
937941 SCLogInitData *SCLogAllocLogInitData(void)
938942 {
939943 SCLogInitData *sc_lid = NULL;
940944
941 if ( (sc_lid = malloc(sizeof(SCLogInitData))) == NULL)
942 return NULL;
945 if ( (sc_lid = malloc(sizeof(SCLogInitData))) == NULL) {
946 SCLogError(SC_ERR_FATAL, "Fatal error encountered initializing the logging subsytem. Out of memory. Exiting...");
947 exit(EXIT_FAILURE);
948 }
943949 memset(sc_lid, 0, sizeof(SCLogInitData));
944950
945951 return sc_lid;
10721078 * \param sc_lid The initialization data for the logging module. If sc_lid is
10731079 * NULL, we would stick to the default configuration for the
10741080 * logging subsystem.
1075 *
1081 * \initonly
10761082 */
10771083 void SCLogInitLogModule(SCLogInitData *sc_lid)
10781084 {
7676 CASE_CODE (SC_ERR_COUNTER_EXCEEDED);
7777 CASE_CODE (SC_ERR_INVALID_CHECKSUM);
7878 CASE_CODE (SC_ERR_SPRINTF);
79 CASE_CODE (SC_ERR_FATAL);
7980 CASE_CODE (SC_ERR_INVALID_ARGUMENT);
8081 CASE_CODE (SC_ERR_SPINLOCK);
8182 CASE_CODE (SC_ERR_INVALID_ENUM_MAP);
7575 struct in_addr *addr = NULL;
7676
7777 if ( (addr = SCMalloc(sizeof(struct in_addr))) == NULL) {
78 SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCHInfoValidateIPV4Address. Exiting...");
79 exit(EXIT_FAILURE);
78 SCLogError(SC_ERR_MEM_ALLOC, "Fatal error encountered in SCHInfoValidateIPV4Address. Mem not allocated");
79 return NULL;
8080 }
8181
8282 if (inet_pton(AF_INET, addr_str, addr) <= 0) {
123123 * \retval user_data On success, pointer to the user_data that has to be sent
124124 * along with the key, to be added to the Radix tree; NULL on
125125 * failure
126 * \initonly
126127 */
127128 static void *SCHInfoAllocUserDataOSPolicy(const char *host_os)
128129 {
129130 int *user_data = NULL;
130131
131 if ( (user_data = SCMalloc(sizeof(int))) == NULL)
132 return NULL;
132 if ( (user_data = SCMalloc(sizeof(int))) == NULL) {
133 SCLogError(SC_ERR_FATAL, "Error allocating memory. Exiting");
134 exit(EXIT_FAILURE);
135 }
133136
134137 /* the host os flavour that has to be sent as user data */
135138 if ( (*user_data = SCMapEnumNameToValue(host_os, sc_hinfo_os_policy_map)) == -1) {
198201 *
199202 * \retval 0 On successfully adding the host os info to the Radix tree
200203 * \retval -1 On failure
204 * \initonly (only specified from config, at the startup)
201205 */
202206 int SCHInfoAddHostOSInfo(char *host_os, char *host_os_ip_range, int is_ipv4)
203207 {
394398
395399 /**
396400 * \brief Load the host os policy information from the configuration.
401 *
402 * \initonly (A mem alloc error should cause an exit failure)
397403 */
398404 void SCHInfoLoadFromConfig(void)
399405 {
2929 #ifndef __UTIL_MEM_H__
3030 #define __UTIL_MEM_H__
3131
32 #include "util-atomic.h"
33 SC_ATOMIC_EXTERN(unsigned int, engine_stage);
34
3235 /* Use this only if you want to debug memory allocation and free()
3336 * It will log a lot of lines more, so think that is a performance killer */
3437
4851 ptrmem = malloc(a); \
4952 if (ptrmem == NULL && a > 0) { \
5053 SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s, while trying " \
51 "to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)a); \
54 "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)a); \
55 if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
56 SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
57 exit(EXIT_FAILURE); \
58 } \
5259 } \
5360 \
5461 global_mem += a; \
5562 if (print_mem_flag == 1) \
56 SCLogInfo("SCMalloc return at %p of size %"PRIdMAX, \
57 ptrmem, (intmax_t)a); \
63 SCLogInfo("SCMalloc return at %p of size %"PRIuMAX, \
64 ptrmem, (uintmax_t)a); \
5865 \
5966 (void*)ptrmem; \
6067 })
6774 ptrmem = realloc(x, a); \
6875 if (ptrmem == NULL && a > 0) { \
6976 SCLogError(SC_ERR_MEM_ALLOC, "SCRealloc failed: %s, while trying " \
70 "to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)a); \
77 "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)a); \
78 if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
79 SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
80 exit(EXIT_FAILURE); \
81 } \
7182 } \
7283 \
7384 global_mem += a; \
7485 if (print_mem_flag == 1) \
75 SCLogInfo("SCRealloc return at %p (old:%p) of size %"PRIdMAX, \
76 ptrmem, x, (intmax_t)a); \
86 SCLogInfo("SCRealloc return at %p (old:%p) of size %"PRIuMAX, \
87 ptrmem, x, (uintmax_t)a); \
7788 \
7889 (void*)ptrmem; \
7990 })
8697 ptrmem = calloc(nm, a); \
8798 if (ptrmem == NULL && a > 0) { \
8899 SCLogError(SC_ERR_MEM_ALLOC, "SCCalloc failed: %s, while trying " \
89 "to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)a); \
100 "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)a); \
101 if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
102 SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
103 exit(EXIT_FAILURE); \
104 } \
90105 } \
91106 \
92107 global_mem += a*nm; \
93108 if (print_mem_flag == 1) \
94 SCLogInfo("SCCalloc return at %p of size %"PRIdMAX" nm %"PRIdMAX, \
95 ptrmem, (intmax_t)a, (intmax_t)nm); \
109 SCLogInfo("SCCalloc return at %p of size %"PRIuMAX" nm %"PRIuMAX, \
110 ptrmem, (uintmax_t)a, (uintmax_t)nm); \
96111 \
97112 (void*)ptrmem; \
98113 })
101116 char *ptrmem = NULL; \
102117 extern size_t global_mem; \
103118 extern uint8_t print_mem_flag; \
104 size_t len = strlen(a); \
105119 \
106120 ptrmem = strdup(a); \
107 if (ptrmem == NULL && len > 0) { \
121 if (ptrmem == NULL) { \
122 size_t len = strlen(a); \
108123 SCLogError(SC_ERR_MEM_ALLOC, "SCStrdup failed: %s, while trying " \
109 "to allocate %"PRIu64" bytes", strerror(errno), (intmax_t)len); \
124 "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)len); \
125 if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
126 SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
127 exit(EXIT_FAILURE); \
128 } \
110129 } \
111130 \
112131 global_mem += len; \
113132 if (print_mem_flag == 1) \
114 SCLogInfo("SCStrdup return at %p of size %"PRIdMAX, \
115 ptrmem, (intmax_t)len); \
133 SCLogInfo("SCStrdup return at %p of size %"PRIuMAX, \
134 ptrmem, (uintmax_t)len); \
116135 \
117136 (void*)ptrmem; \
118137 })
125144 })
126145
127146 #else /* DBG_MEM_ALLOC */
128
129147 #if 0
130 #define SCMalloc(a) ({ \
131 void *ptrmem = malloc(a); \
132 if (ptrmem == NULL) { \
133 SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s, while trying " \
134 "to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)a); \
135 } \
136 (void*)ptrmem; \
137 })
138
139 #define SCRealloc(x, a) ({ \
140 void *ptrmem = realloc(x, a); \
141 if (ptrmem == NULL) { \
142 SCLogError(SC_ERR_MEM_ALLOC, "SCRealloc failed: %s, while trying " \
143 "to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)a); \
144 } \
145 (void*)ptrmem; \
146 })
147
148 #define SCCalloc(nm, a) ({ \
149 void *ptrmem = calloc(nm, a); \
150 if (ptrmem == NULL) { \
151 SCLogError(SC_ERR_MEM_ALLOC, "SCCalloc failed: %s, while trying " \
152 "to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)a); \
153 } \
154 (void*)ptrmem; \
155 })
156
157 #define SCStrdup(a) ({ \
158 char *ptrmem = strdup(a); \
159 if (ptrmem == NULL) { \
160 SCLogError(SC_ERR_MEM_ALLOC, "SCStrdup failed: %s, while trying " \
161 "to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)strlen(a)); \
162 } \
163 (void*)ptrmem; \
164 })
165 #endif
148 /* without any checks */
166149 #define SCMalloc malloc
167150 #define SCRealloc realloc
168151 #define SCCalloc calloc
169152 #define SCStrdup strdup
170
171153 #define SCFree(a) free((a))
154 #endif
155
156 #define SCMalloc(a) ({ \
157 void *ptrmem = NULL; \
158 \
159 ptrmem = malloc(a); \
160 if (ptrmem == NULL && a > 0) { \
161 SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s, while trying " \
162 "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)a); \
163 if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
164 SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
165 exit(EXIT_FAILURE); \
166 } \
167 } \
168 (void*)ptrmem; \
169 })
170
171 #define SCRealloc(x, a) ({ \
172 void *ptrmem = NULL; \
173 \
174 ptrmem = realloc(x, a); \
175 if (ptrmem == NULL && a > 0) { \
176 SCLogError(SC_ERR_MEM_ALLOC, "SCRealloc failed: %s, while trying " \
177 "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)a); \
178 if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
179 SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
180 exit(EXIT_FAILURE); \
181 } \
182 } \
183 (void*)ptrmem; \
184 })
185
186 #define SCCalloc(nm, a) ({ \
187 void *ptrmem = NULL; \
188 \
189 ptrmem = calloc(nm, a); \
190 if (ptrmem == NULL && a > 0) { \
191 SCLogError(SC_ERR_MEM_ALLOC, "SCCalloc failed: %s, while trying " \
192 "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)a); \
193 if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
194 SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
195 exit(EXIT_FAILURE); \
196 } \
197 } \
198 (void*)ptrmem; \
199 })
200
201 #define SCStrdup(a) ({ \
202 char *ptrmem = NULL; \
203 \
204 ptrmem = strdup(a); \
205 if (ptrmem == NULL) { \
206 size_t len = strlen(a); \
207 SCLogError(SC_ERR_MEM_ALLOC, "SCStrdup failed: %s, while trying " \
208 "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)len); \
209 if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
210 SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
211 exit(EXIT_FAILURE); \
212 } \
213 } \
214 (void*)ptrmem; \
215 })
216
217 #define SCFree(a) ({ \
218 free(a); \
219 })
172220
173221 #endif /* DBG_MEM_ALLOC */
174222
122122 printf("\n");
123123 }
124124
125 /**
126 * \brief B2gAllocPattern allocates a new pattern structure
127 * and initialize the data
128 * \initonly
129 */
125130 static inline B2gPattern *B2gAllocPattern(MpmCtx *mpm_ctx) {
126131 B2gPattern *p = SCMalloc(sizeof(B2gPattern));
127132 if (p == NULL)
274279 * \param pid pattern id
275280 * \param sid signature id (internal id)
276281 * \param flags pattern MPM_PATTERN_* flags
282 *
283 * \initonly
277284 */
278285 static int B2gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) {
279286 B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx;
140140 {
141141 SCRadixUserData *user_data = SCMalloc(sizeof(SCRadixUserData));
142142 if (user_data == NULL) {
143 SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
143144 return NULL;
144145 }
145146
475476 SCRadixNode *node = NULL;
476477
477478 if ( (node = SCMalloc(sizeof(SCRadixNode))) == NULL) {
478 SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCRadixCreateNode. Exiting...");
479 exit(EXIT_FAILURE);
479 SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCRadixCreateNode. Mem not allocated...");
480 return NULL;
480481 }
481482 memset(node, 0, sizeof(SCRadixNode));
482483
510511 * cleanup API to free the user suppplied data
511512 *
512513 * \retval tree The newly created radix tree on success
514 *
515 * \initonly (all radix trees should be created at init)
513516 */
514517 SCRadixTree *SCRadixCreateRadixTree(void (*Free)(void*), void (*PrintData)(void*))
515518 {
614617 /* the very first element in the radix tree */
615618 if (tree->head == NULL) {
616619 node = SCRadixCreateNode();
620 if (node == NULL)
621 return NULL;
617622 node->prefix = prefix;
618623 node->bit = prefix->bitlen;
619624 tree->head = node;
631636 node->netmask_cnt++;
632637 if ( (node->netmasks = SCRealloc(node->netmasks, (node->netmask_cnt *
633638 sizeof(uint8_t)))) == NULL) {
634 SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCRadixAddKey. Exiting...");
635 exit(EXIT_FAILURE);
639 SCLogError(SC_ERR_MEM_ALLOC, "Fatal error encountered in SCRadixAddKey. Mem not allocated");
640 return NULL;
636641 }
637642 node->netmasks[0] = netmask;
638643 return node;
749754 node->netmask_cnt++;
750755 if ( (node->netmasks = SCRealloc(node->netmasks, (node->netmask_cnt *
751756 sizeof(uint8_t)))) == NULL) {
752 SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCRadixAddKey. Exiting...");
753 exit(EXIT_FAILURE);
757 SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCRadixAddKey. Mem not allocated...");
758 return NULL;
754759 }
755760
756761 if (node->netmask_cnt == 1) {
821826
822827 if ( (inter_node->netmasks = SCMalloc((node->netmask_cnt - i) *
823828 sizeof(uint8_t))) == NULL) {
824 SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCRadixAddKey. Exiting...");
825 exit(EXIT_FAILURE);
829 SCLogError(SC_ERR_MEM_ALLOC, "Fatal error encountered in SCRadixAddKey. Mem not allocated...");
830 return NULL;
826831 }
827832
828833 for (j = 0; j < (node->netmask_cnt - i); j++)
6161 * \param str pointer to the pattern string
6262 * \param size length of the string
6363 * \retval BmCtx pointer to the newly created Context for the pattern
64 * \initonly BoyerMoore contexts should be created at init
6465 */
6566 BmCtx *BoyerMooreCtxInit(uint8_t *needle, uint32_t needle_len) {
6667 BmCtx *new = SCMalloc(sizeof(BmCtx));
7980 }
8081
8182 /* Prepare good Suffixes */
82 PreBmGs(needle, needle_len, new->bmGs);
83 if (PreBmGs(needle, needle_len, new->bmGs) == -1) {
84 SCLogError(SC_ERR_FATAL, "Fatal error encountered in BooyerMooreCtxInit. Exiting...");
85 exit(EXIT_FAILURE);
86 }
87
8388
8489 return new;
8590 }
152157 * \param x pointer to the pattern string
153158 * \param m length of the string
154159 * \param bmGs pointer to an empty array that will hold the prefixes (shifts)
155 */
156 void PreBmGs(const uint8_t *x, int32_t m, int32_t *bmGs) {
160 * \retval 0 ok, -1 failed
161 */
162 int PreBmGs(const uint8_t *x, int32_t m, int32_t *bmGs) {
157163 int32_t i, j;
158164 int32_t *suff;
159165
160166 suff = SCMalloc(sizeof(int32_t) * (m + 1));
161167 if (suff == NULL)
162 return;
168 return -1;
163169
164170 BoyerMooreSuffixes(x, m, suff);
165171
177183 for (i = 0; i <= m - 2; ++i)
178184 bmGs[m - 1 - suff[i]] = m - 1 - i;
179185 SCFree(suff);
186 return 0;
180187 }
181188
182189 /**
4141 void BoyerMooreCtxToNocase(BmCtx *, uint8_t *, uint32_t);
4242 void PreBmBc(const uint8_t *x, int32_t m, int32_t *bmBc);
4343 void BoyerMooreSuffixes(const uint8_t *x, int32_t m, int32_t *suff);
44 void PreBmGs(const uint8_t *x, int32_t m, int32_t *bmGs);
44 int PreBmGs(const uint8_t *, int32_t, int32_t *);
4545 uint8_t *BoyerMoore(uint8_t *x, int32_t m, uint8_t *y, int32_t n, int32_t *bmGs, int32_t *bmBc);
4646 void PreBmBcNocase(const uint8_t *x, int32_t m, int32_t *bmBc);
4747 void BoyerMooreSuffixesNocase(const uint8_t *x, int32_t m, int32_t *suff);
12701270
12711271 Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
12721272 ThreadVars th_v;
1273 DetectEngineThreadCtx *det_ctx;
1273 DetectEngineThreadCtx *det_ctx = NULL;
12741274 int alerts = 0;
12751275
12761276 memset(&th_v, 0, sizeof(th_v));
13631363 Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10");
13641364
13651365 ThreadVars th_v;
1366 DetectEngineThreadCtx *det_ctx;
1366 DetectEngineThreadCtx *det_ctx = NULL;
13671367 int alerts = 0;
13681368
13691369 memset(&th_v, 0, sizeof(th_v));
14581458
14591459 Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
14601460 ThreadVars th_v;
1461 DetectEngineThreadCtx *det_ctx;
1461 DetectEngineThreadCtx *det_ctx = NULL;
14621462 int alerts10 = 0;
14631463 int alerts11 = 0;
14641464 int alerts12 = 0;
15741574
15751575 Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP);
15761576 ThreadVars th_v;
1577 DetectEngineThreadCtx *det_ctx;
1577 DetectEngineThreadCtx *det_ctx = NULL;
15781578 int alerts10 = 0;
15791579 int alerts11 = 0;
15801580 int alerts12 = 0;
238238 #
239239 # stream:
240240 # memcap: 33554432 # 32mb tcp session memcap
241 # checksum_validation: yes # To validate the checksum of received
242 # packet. If csum validation is specified as
243 # "yes", then packet with invalid csum will not
244 # be processed by the engine stream/app layer.
241245 # max_sessions: 262144 # 256k concurrent sessions
242246 # prealloc_sessions: 32768 # 32k sessions prealloc'd
243247 # midstream: false # don't allow midstream session pickups
247251 # depth: 1048576 # 1 MB reassembly depth
248252 stream:
249253 memcap: 33554432
254 checksum_validation: yes
250255 reassembly:
251256 memcap: 67108864
252257 depth: 1048576