1 /* Copyright (C) 2007-2019 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18 /**
19 * Stub for per HTTP header detection keyword. Meant to be included into
20 * a C file.
21 */
22
23 /**
24 * \ingroup httplayer
25 *
26 * @{
27 */
28
29 #include "suricata-common.h"
30 #include "threads.h"
31 #include "decode.h"
32 #include "flow.h"
33 #include "app-layer.h"
34 #include "app-layer-parser.h"
35 #include "app-layer-protos.h"
36 #include "app-layer-htp.h"
37
38 #include "detect.h"
39 #include "detect-parse.h"
40 #include "detect-engine.h"
41 #include "detect-engine-mpm.h"
42 #include "detect-engine-state.h"
43 #include "detect-engine-prefilter.h"
44 #include "detect-engine-content-inspection.h"
45 #include "detect-content.h"
46 #include "detect-http-header.h"
47
48 #include "util-debug.h"
49
50 static int g_buffer_id = 0;
51
52 #ifdef KEYWORD_TOSERVER
GetRequestData(DetectEngineThreadCtx * det_ctx,const DetectEngineTransforms * transforms,Flow * _f,const uint8_t _flow_flags,void * txv,const int list_id)53 static InspectionBuffer *GetRequestData(DetectEngineThreadCtx *det_ctx,
54 const DetectEngineTransforms *transforms, Flow *_f,
55 const uint8_t _flow_flags, void *txv, const int list_id)
56 {
57 SCEnter();
58
59 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
60 if (buffer->inspect == NULL) {
61 htp_tx_t *tx = (htp_tx_t *)txv;
62
63 if (tx->request_headers == NULL)
64 return NULL;
65
66 htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers,
67 HEADER_NAME);
68 if (h == NULL || h->value == NULL) {
69 SCLogDebug("HTTP %s header not present in this request",
70 HEADER_NAME);
71 return NULL;
72 }
73
74 const uint32_t data_len = bstr_len(h->value);
75 const uint8_t *data = bstr_ptr(h->value);
76
77 InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len);
78 InspectionBufferApplyTransforms(buffer, transforms);
79 }
80
81 return buffer;
82 }
83
GetRequestData2(DetectEngineThreadCtx * det_ctx,const DetectEngineTransforms * transforms,Flow * _f,const uint8_t _flow_flags,void * txv,const int list_id)84 static InspectionBuffer *GetRequestData2(DetectEngineThreadCtx *det_ctx,
85 const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
86 const int list_id)
87 {
88 SCEnter();
89
90 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
91 if (buffer->inspect == NULL) {
92 uint32_t b_len = 0;
93 const uint8_t *b = NULL;
94
95 if (rs_http2_tx_get_header_value(txv, STREAM_TOSERVER, HEADER_NAME, &b, &b_len) != 1)
96 return NULL;
97 if (b == NULL || b_len == 0)
98 return NULL;
99
100 InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
101 InspectionBufferApplyTransforms(buffer, transforms);
102 }
103
104 return buffer;
105 }
106
107 #endif
108 #ifdef KEYWORD_TOCLIENT
GetResponseData(DetectEngineThreadCtx * det_ctx,const DetectEngineTransforms * transforms,Flow * _f,const uint8_t _flow_flags,void * txv,const int list_id)109 static InspectionBuffer *GetResponseData(DetectEngineThreadCtx *det_ctx,
110 const DetectEngineTransforms *transforms, Flow *_f,
111 const uint8_t _flow_flags, void *txv, const int list_id)
112 {
113 SCEnter();
114
115 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
116 if (buffer->inspect == NULL) {
117 htp_tx_t *tx = (htp_tx_t *)txv;
118
119 if (tx->response_headers == NULL)
120 return NULL;
121
122 htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->response_headers,
123 HEADER_NAME);
124 if (h == NULL || h->value == NULL) {
125 SCLogDebug("HTTP %s header not present in this request",
126 HEADER_NAME);
127 return NULL;
128 }
129
130 const uint32_t data_len = bstr_len(h->value);
131 const uint8_t *data = bstr_ptr(h->value);
132
133 InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len);
134 InspectionBufferApplyTransforms(buffer, transforms);
135 }
136
137 return buffer;
138 }
139
GetResponseData2(DetectEngineThreadCtx * det_ctx,const DetectEngineTransforms * transforms,Flow * _f,const uint8_t _flow_flags,void * txv,const int list_id)140 static InspectionBuffer *GetResponseData2(DetectEngineThreadCtx *det_ctx,
141 const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
142 const int list_id)
143 {
144 SCEnter();
145
146 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
147 if (buffer->inspect == NULL) {
148 uint32_t b_len = 0;
149 const uint8_t *b = NULL;
150
151 if (rs_http2_tx_get_header_value(txv, STREAM_TOCLIENT, HEADER_NAME, &b, &b_len) != 1)
152 return NULL;
153 if (b == NULL || b_len == 0)
154 return NULL;
155
156 InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
157 InspectionBufferApplyTransforms(buffer, transforms);
158 }
159
160 return buffer;
161 }
162 #endif
163
164 /**
165 * \brief this function setup the http.header keyword used in the rule
166 *
167 * \param de_ctx Pointer to the Detection Engine Context
168 * \param s Pointer to the Signature to which the current keyword belongs
169 * \param str Should hold an empty string always
170 *
171 * \retval 0 On success
172 */
DetectHttpHeadersSetupSticky(DetectEngineCtx * de_ctx,Signature * s,const char * str)173 static int DetectHttpHeadersSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
174 {
175 if (DetectBufferSetActiveList(s, g_buffer_id) < 0)
176 return -1;
177
178 if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0)
179 return -1;
180
181 return 0;
182 }
183
DetectHttpHeadersRegisterStub(void)184 static void DetectHttpHeadersRegisterStub(void)
185 {
186 sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME;
187 #ifdef KEYWORD_NAME_LEGACY
188 sigmatch_table[KEYWORD_ID].alias = KEYWORD_NAME_LEGACY;
189 #endif
190 sigmatch_table[KEYWORD_ID].desc = KEYWORD_NAME " sticky buffer for the " BUFFER_DESC;
191 sigmatch_table[KEYWORD_ID].url = "/rules/" KEYWORD_DOC;
192 sigmatch_table[KEYWORD_ID].Setup = DetectHttpHeadersSetupSticky;
193 sigmatch_table[KEYWORD_ID].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
194
195 #ifdef KEYWORD_TOSERVER
196 DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
197 GetRequestData, ALPROTO_HTTP, HTP_REQUEST_HEADERS);
198 DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
199 GetRequestData2, ALPROTO_HTTP2, HTTP2StateDataClient);
200 #endif
201 #ifdef KEYWORD_TOCLIENT
202 DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister,
203 GetResponseData, ALPROTO_HTTP, HTP_RESPONSE_HEADERS);
204 DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister,
205 GetResponseData2, ALPROTO_HTTP2, HTTP2StateDataServer);
206 #endif
207 #ifdef KEYWORD_TOSERVER
208 DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP, SIG_FLAG_TOSERVER,
209 HTP_REQUEST_HEADERS, DetectEngineInspectBufferGeneric, GetRequestData);
210 DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOSERVER,
211 HTTP2StateDataClient, DetectEngineInspectBufferGeneric, GetRequestData2);
212 #endif
213 #ifdef KEYWORD_TOCLIENT
214 DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP, SIG_FLAG_TOCLIENT,
215 HTP_RESPONSE_HEADERS, DetectEngineInspectBufferGeneric, GetResponseData);
216 DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_HTTP2, SIG_FLAG_TOCLIENT,
217 HTTP2StateDataServer, DetectEngineInspectBufferGeneric, GetResponseData2);
218 #endif
219
220 DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
221
222 g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
223 }
224