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