/src/suricata8/src/detect-frame.c
Line | Count | Source |
1 | | /* Copyright (C) 2021-2022 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 | | * \file |
20 | | */ |
21 | | |
22 | | #include "suricata-common.h" |
23 | | #include "threads.h" |
24 | | #include "decode.h" |
25 | | #include "detect.h" |
26 | | |
27 | | #include "app-layer-frames.h" |
28 | | #include "app-layer-parser.h" |
29 | | |
30 | | #include "detect-parse.h" |
31 | | #include "detect-engine.h" |
32 | | #include "detect-engine-buffer.h" |
33 | | #include "detect-engine-mpm.h" |
34 | | #include "detect-engine-prefilter.h" |
35 | | #include "detect-content.h" |
36 | | #include "detect-engine-content-inspection.h" |
37 | | #include "detect-frame.h" |
38 | | |
39 | | #include "flow.h" |
40 | | #include "flow-util.h" |
41 | | #include "flow-var.h" |
42 | | |
43 | | #include "conf.h" |
44 | | #include "conf-yaml-loader.h" |
45 | | |
46 | | #include "util-debug.h" |
47 | | #include "util-unittest.h" |
48 | | #include "util-spm.h" |
49 | | #include "util-print.h" |
50 | | |
51 | | static int DetectFrameSetup(DetectEngineCtx *, Signature *, const char *); |
52 | | |
53 | | /** |
54 | | * \brief this function setup the sticky buffer used in the rule |
55 | | * |
56 | | * \param de_ctx Pointer to the Detection Engine Context |
57 | | * \param s Pointer to the Signature to which the current keyword belongs |
58 | | * \param str The frame name. Can be short name 'pdu' or full name 'sip.pdu' |
59 | | * |
60 | | * \retval 0 On success |
61 | | * \retval -1 On failure |
62 | | */ |
63 | | static int DetectFrameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) |
64 | 39.5k | { |
65 | 39.5k | char value[256] = ""; |
66 | 39.5k | strlcpy(value, str, sizeof(value)); |
67 | 39.5k | char buffer_name[512] = ""; // for registering in detect API we always need <proto>.<frame>. |
68 | | |
69 | 39.5k | const bool is_tcp = DetectProtoContainsProto(&s->proto, IPPROTO_TCP); |
70 | 39.5k | const bool is_udp = DetectProtoContainsProto(&s->proto, IPPROTO_UDP); |
71 | 39.5k | if (!(is_tcp || is_udp)) { |
72 | 319 | SCLogError("'frame' keyword only supported for TCP and UDP"); |
73 | 319 | return -1; |
74 | 319 | } |
75 | | |
76 | 39.2k | char *dot = strchr(value, '.'); |
77 | 39.2k | if (dot != NULL) |
78 | 32.6k | *dot++ = '\0'; |
79 | 39.2k | const char *val = dot ? dot : value; |
80 | 39.2k | const char *proto = dot ? value : NULL; |
81 | | |
82 | 39.2k | bool is_short = false; |
83 | 39.2k | AppProto keyword_alproto = ALPROTO_UNKNOWN; |
84 | 39.2k | AppProto rule_alproto = s->alproto; |
85 | | |
86 | 39.2k | if (proto != NULL) { |
87 | 32.6k | keyword_alproto = StringToAppProto(proto); |
88 | 32.6k | if (!AppProtoIsValid(keyword_alproto)) { |
89 | 18.5k | is_short = true; |
90 | 18.5k | keyword_alproto = rule_alproto; |
91 | 18.5k | } |
92 | 32.6k | } else { |
93 | 6.61k | is_short = true; |
94 | 6.61k | keyword_alproto = rule_alproto; |
95 | 6.61k | } |
96 | | |
97 | 39.2k | if (is_short && rule_alproto == ALPROTO_UNKNOWN) { |
98 | 481 | SCLogError("rule protocol unknown, can't use shorthand notation for frame '%s'", str); |
99 | 481 | return -1; |
100 | 38.7k | } else if (rule_alproto == ALPROTO_UNKNOWN) { |
101 | 1.20k | if (SCDetectSignatureSetAppProto(s, keyword_alproto) < 0) |
102 | 2 | return -1; |
103 | 37.5k | } else if (!AppProtoEquals(rule_alproto, keyword_alproto)) { |
104 | 213 | SCLogError("frame '%s' protocol '%s' mismatch with rule protocol '%s'", str, |
105 | 213 | AppProtoToString(keyword_alproto), AppProtoToString(s->alproto)); |
106 | 213 | return -1; |
107 | 213 | } |
108 | | |
109 | 38.5k | const char *frame_str = is_short ? str : val; |
110 | 38.5k | int raw_frame_type = -1; |
111 | 38.5k | if (is_tcp) { |
112 | 38.2k | if (strcmp(frame_str, "stream") == 0) { |
113 | 584 | raw_frame_type = FRAME_STREAM_TYPE; |
114 | 37.6k | } else { |
115 | 37.6k | raw_frame_type = |
116 | 37.6k | AppLayerParserGetFrameIdByName(IPPROTO_TCP, keyword_alproto, frame_str); |
117 | 37.6k | } |
118 | 38.2k | } |
119 | 38.5k | if (is_udp && raw_frame_type < 0) |
120 | 1.30k | raw_frame_type = AppLayerParserGetFrameIdByName(IPPROTO_UDP, keyword_alproto, frame_str); |
121 | 38.5k | if (raw_frame_type < 0) { |
122 | 5.70k | SCLogError("unknown frame '%s' for protocol '%s'", frame_str, proto); |
123 | 5.70k | return -1; |
124 | 5.70k | } |
125 | 32.8k | BUG_ON(raw_frame_type > UINT8_MAX); |
126 | | |
127 | 32.8k | if (is_short) { |
128 | 21.1k | snprintf(buffer_name, sizeof(buffer_name), "%s.%s", AppProtoToString(s->alproto), str); |
129 | 21.1k | SCLogDebug("short name: %s", buffer_name); |
130 | 21.1k | } else { |
131 | 11.7k | strlcpy(buffer_name, str, sizeof(buffer_name)); |
132 | 11.7k | SCLogDebug("long name: %s", buffer_name); |
133 | 11.7k | } |
134 | | // make sure the buffer name is lowercase |
135 | | // even if the protocol accepted case-insensitive frame name |
136 | 443k | for (size_t i = 0; i < sizeof(buffer_name) && buffer_name[i]; i++) { |
137 | 411k | buffer_name[i] = u8_tolower(buffer_name[i]); |
138 | 411k | } |
139 | | |
140 | 32.8k | uint8_t frame_type = (uint8_t)raw_frame_type; |
141 | | /* TODO we can have TS and TC specific frames */ |
142 | 32.8k | const int buffer_id = DetectEngineBufferTypeRegisterWithFrameEngines(de_ctx, buffer_name, |
143 | 32.8k | SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT, keyword_alproto, frame_type); |
144 | 32.8k | if (buffer_id < 0) |
145 | 0 | return -1; |
146 | | |
147 | 32.8k | if (SCDetectBufferSetActiveList(de_ctx, s, buffer_id) < 0) |
148 | 18 | return -1; |
149 | | |
150 | 32.8k | FrameConfigEnable(keyword_alproto, frame_type); |
151 | 32.8k | return 0; |
152 | 32.8k | } |
153 | | |
154 | | #ifdef UNITTESTS |
155 | | |
156 | | static int DetectFrameTestBadRules(void) |
157 | | { |
158 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
159 | | FAIL_IF_NULL(de_ctx); |
160 | | |
161 | | const char *sigs[] = { |
162 | | "alert tcp-pkt any any -> any any (frame:tls.pdu; content:\"a\"; sid:1;)", |
163 | | "alert udp any any -> any any (frame:tls.pdu; content:\"a\"; sid:2;)", |
164 | | "alert smb any any -> any any (frame:tls.pdu; content:\"a\"; sid:3;)", |
165 | | "alert tcp any any -> any any (frame:tls; content:\"a\"; sid:4;)", |
166 | | "alert tls any any -> any any (content:\"abc\"; frame:tls.pdu; content:\"a\"; sid:5;)", |
167 | | "alert tls any any -> any any (tls.version:1.0; frame:tls.pdu; content:\"a\"; sid:6;)", |
168 | | "alert tls any any -> any any (frame:smb1.pdu; content:\"a\"; sid:7;)", |
169 | | NULL, |
170 | | }; |
171 | | |
172 | | const char **sig = sigs; |
173 | | while (*sig) { |
174 | | SCLogDebug("sig %s", *sig); |
175 | | Signature *s = DetectEngineAppendSig(de_ctx, *sig); |
176 | | FAIL_IF_NOT_NULL(s); |
177 | | sig++; |
178 | | } |
179 | | |
180 | | DetectEngineCtxFree(de_ctx); |
181 | | PASS; |
182 | | } |
183 | | |
184 | | static void DetectFrameRegisterTests(void) |
185 | | { |
186 | | UtRegisterTest("DetectFrameTestBadRules", DetectFrameTestBadRules); |
187 | | } |
188 | | #endif |
189 | | |
190 | | /** |
191 | | * \brief Registration function for keyword: ja3_hash |
192 | | */ |
193 | | void DetectFrameRegister(void) |
194 | 12 | { |
195 | 12 | sigmatch_table[DETECT_FRAME].name = "frame"; |
196 | 12 | sigmatch_table[DETECT_FRAME].desc = "sticky buffer for inspecting app-layer frames"; |
197 | 12 | sigmatch_table[DETECT_FRAME].Setup = DetectFrameSetup; |
198 | 12 | sigmatch_table[DETECT_FRAME].flags = SIGMATCH_INFO_STICKY_BUFFER; |
199 | | #ifdef UNITTESTS |
200 | | sigmatch_table[DETECT_FRAME].RegisterTests = DetectFrameRegisterTests; |
201 | | #endif |
202 | 12 | } |