/src/suricata7/src/detect-transform-dotprefix.c
Line | Count | Source |
1 | | /* Copyright (C) 2020 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 | | * \author Jeff Lucovsky <jeff@lucovsky.org> |
22 | | * |
23 | | * Implements the dotprefix transformation |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | |
28 | | #include "detect.h" |
29 | | #include "detect-engine.h" |
30 | | #include "detect-engine-prefilter.h" |
31 | | #include "detect-parse.h" |
32 | | #include "detect-transform-dotprefix.h" |
33 | | #include "detect-engine-build.h" |
34 | | |
35 | | #include "util-unittest.h" |
36 | | #include "util-print.h" |
37 | | #include "util-memrchr.h" |
38 | | #include "util-memcpy.h" |
39 | | |
40 | | static int DetectTransformDotPrefixSetup (DetectEngineCtx *, Signature *, const char *); |
41 | | #ifdef UNITTESTS |
42 | | static void DetectTransformDotPrefixRegisterTests(void); |
43 | | #endif |
44 | | static void TransformDotPrefix(InspectionBuffer *buffer, void *options); |
45 | | |
46 | | void DetectTransformDotPrefixRegister(void) |
47 | 34 | { |
48 | 34 | sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].name = "dotprefix"; |
49 | 34 | sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].desc = |
50 | 34 | "modify buffer to extract the dotprefix"; |
51 | 34 | sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].url = |
52 | 34 | "/rules/transforms.html#dotprefix"; |
53 | 34 | sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].Transform = TransformDotPrefix; |
54 | 34 | sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].Setup = DetectTransformDotPrefixSetup; |
55 | | #ifdef UNITTESTS |
56 | | sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].RegisterTests = |
57 | | DetectTransformDotPrefixRegisterTests; |
58 | | #endif |
59 | 34 | sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].flags |= SIGMATCH_NOOPT; |
60 | 34 | } |
61 | | |
62 | | /** |
63 | | * \internal |
64 | | * \brief Extract the dotprefix, if any, the last pattern match, either content or uricontent |
65 | | * \param det_ctx detection engine ctx |
66 | | * \param s signature |
67 | | * \param nullstr should be null |
68 | | * \retval 0 ok |
69 | | * \retval -1 failure |
70 | | */ |
71 | | static int DetectTransformDotPrefixSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) |
72 | 1.65k | { |
73 | 1.65k | SCEnter(); |
74 | 1.65k | int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_DOTPREFIX, NULL); |
75 | 1.65k | SCReturnInt(r); |
76 | 1.65k | } |
77 | | |
78 | | /** |
79 | | * \brief Return the dotprefix, if any, in the last pattern match. |
80 | | * |
81 | | * Input values are modified by prefixing with a ".". |
82 | | * |
83 | | * Rule: "alert dns any any -> any any (dns_query; dotprefix; content:".google.com"; sid:1;)" |
84 | | * 1. hello.google.com --> match |
85 | | * 2. hey.agoogle.com --> no match |
86 | | * 3. agoogle.com --> no match |
87 | | * 4. something.google.com.au --> match |
88 | | * 5. google.com --> match |
89 | | * |
90 | | * To match on the dotprefix only: |
91 | | * Rule: "alert dns any any -> any any (dns_query; dotprefix; content:".google.com"; endswith; sid:1;)" |
92 | | * |
93 | | * 1. hello.google.com --> match |
94 | | * 2. hey.agoogle.com --> no match |
95 | | * 3. agoogle.com --> no match |
96 | | * 4. something.google.com.au --> no match |
97 | | * 5. google.com --> match |
98 | | * |
99 | | * To match on a TLD: |
100 | | * Rule: "alert dns any any -> any any (dns_query; dotprefix; content:".co.uk"; endswith; sid:1;)" |
101 | | * |
102 | | * 1. hello.google.com --> no match |
103 | | * 2. hey.agoogle.com --> no match |
104 | | * 3. agoogle.com --> no match |
105 | | * 4. something.google.co.uk --> match |
106 | | * 5. google.com --> no match |
107 | | */ |
108 | | static void TransformDotPrefix(InspectionBuffer *buffer, void *options) |
109 | 553 | { |
110 | 553 | const size_t input_len = buffer->inspect_len; |
111 | | |
112 | 553 | if (input_len) { |
113 | | // For the leading '.' |
114 | 553 | uint8_t *output = InspectionBufferCheckAndExpand(buffer, input_len + 1); |
115 | 553 | if (output == NULL) { |
116 | 0 | return; |
117 | 0 | } |
118 | | |
119 | 553 | memmove(&output[1], buffer->inspect, input_len); |
120 | 553 | output[0] = '.'; |
121 | 553 | InspectionBufferTruncate(buffer, input_len + 1); |
122 | 553 | } |
123 | 553 | } |
124 | | |
125 | | #ifdef UNITTESTS |
126 | | static int DetectTransformDotPrefixTest01(void) |
127 | | { |
128 | | const uint8_t *input = (const uint8_t *)"example.com"; |
129 | | uint32_t input_len = strlen((char *)input); |
130 | | |
131 | | const char *result = ".example.com"; |
132 | | uint32_t result_len = strlen((char *)result); |
133 | | |
134 | | InspectionBuffer buffer; |
135 | | InspectionBufferInit(&buffer, input_len); |
136 | | InspectionBufferSetup(NULL, -1, &buffer, input, input_len); |
137 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
138 | | TransformDotPrefix(&buffer, NULL); |
139 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
140 | | FAIL_IF_NOT(buffer.inspect_len == result_len); |
141 | | FAIL_IF_NOT(strncmp(result, (const char *)buffer.inspect, result_len) == 0); |
142 | | InspectionBufferFree(&buffer); |
143 | | PASS; |
144 | | } |
145 | | |
146 | | static int DetectTransformDotPrefixTest02(void) |
147 | | { |
148 | | const uint8_t *input = (const uint8_t *)"hello.example.com"; |
149 | | uint32_t input_len = strlen((char *)input); |
150 | | |
151 | | const char *result = ".hello.example.com"; |
152 | | uint32_t result_len = strlen((char *)result); |
153 | | |
154 | | InspectionBuffer buffer; |
155 | | InspectionBufferInit(&buffer, input_len); |
156 | | InspectionBufferSetup(NULL, -1, &buffer, input, input_len); |
157 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
158 | | TransformDotPrefix(&buffer, NULL); |
159 | | PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); |
160 | | FAIL_IF_NOT(buffer.inspect_len == result_len); |
161 | | FAIL_IF_NOT(strncmp(result, (const char *)buffer.inspect, result_len) == 0); |
162 | | InspectionBufferFree(&buffer); |
163 | | PASS; |
164 | | } |
165 | | |
166 | | static int DetectTransformDotPrefixTest03(void) |
167 | | { |
168 | | const char rule[] = "alert dns any any -> any any (dns.query; dotprefix; content:\".google.com\"; sid:1;)"; |
169 | | ThreadVars th_v; |
170 | | DetectEngineThreadCtx *det_ctx = NULL; |
171 | | memset(&th_v, 0, sizeof(th_v)); |
172 | | |
173 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
174 | | FAIL_IF_NULL(de_ctx); |
175 | | Signature *s = DetectEngineAppendSig(de_ctx, rule); |
176 | | FAIL_IF_NULL(s); |
177 | | SigGroupBuild(de_ctx); |
178 | | DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); |
179 | | DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); |
180 | | DetectEngineCtxFree(de_ctx); |
181 | | PASS; |
182 | | } |
183 | | |
184 | | static void DetectTransformDotPrefixRegisterTests(void) |
185 | | { |
186 | | UtRegisterTest("DetectTransformDotPrefixTest01", DetectTransformDotPrefixTest01); |
187 | | UtRegisterTest("DetectTransformDotPrefixTest02", DetectTransformDotPrefixTest02); |
188 | | UtRegisterTest("DetectTransformDotPrefixTest03", DetectTransformDotPrefixTest03); |
189 | | } |
190 | | #endif |