1 /*
2 * sf_snort_plugin_hdropts.c
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation. You may not use, modify or
7 * distribute this program under any other version of the GNU General
8 * Public License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
20 * Copyright (C) 2005-2013 Sourcefire, Inc.
21 *
22 * Author: Steve Sturges
23 * Andy Mullican
24 *
25 * Date: 5/2005
26 *
27 *
28 * Header Option operations for dynamic rule engine
29 */
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include "sf_dynamic_define.h"
35 #include "sf_snort_packet.h"
36 #include "sf_snort_plugin_api.h"
37 #include "sf_dynamic_engine.h"
38 #include "ipv6_port.h"
39
40 static int checkHdrOptInternal(void *, HdrOptCheck *);
41
ValidateHeaderCheck(Rule * rule,HdrOptCheck * optData)42 int ValidateHeaderCheck(Rule *rule, HdrOptCheck *optData)
43 {
44 int retVal =0;
45
46 switch (optData->hdrField)
47 {
48 case IP_HDR_OPTIONS:
49 if ((optData->op != CHECK_EQ) &&
50 (optData->op != CHECK_NEQ))
51 {
52 _ded.errMsg("Invalid operator for Check Header IP Options: %d "
53 "for dynamic rule [%d:%d].\n"
54 "Must be either CHECK_EQ (option present) or "
55 "CHECK_NEQ (not present).\n",
56 optData->op, rule->info.genID, rule->info.sigID);
57 retVal = -1;
58 }
59 break;
60 case TCP_HDR_OPTIONS:
61 if ((optData->op != CHECK_EQ) &&
62 (optData->op != CHECK_NEQ))
63 {
64 _ded.errMsg("Invalid operator for Check Header IP Options: %d "
65 "for dynamic rule [%d:%d].\n"
66 "Must be either CHECK_EQ (option present) or "
67 "CHECK_NEQ (not present).\n",
68 optData->op, rule->info.genID, rule->info.sigID);
69 retVal = -1;
70 }
71 break;
72 case IP_HDR_FRAGBITS:
73 if ((optData->op != CHECK_EQ) &&
74 (optData->op != CHECK_ALL) &&
75 (optData->op != CHECK_ATLEASTONE) &&
76 (optData->op != CHECK_NONE))
77 {
78 _ded.errMsg("Invalid operator for Check IP Fragbits: %d "
79 "for dynamic rule [%d:%d].\n",
80 optData->op, rule->info.genID, rule->info.sigID);
81 retVal = -1;
82 }
83 }
84 return retVal;
85 }
86
checkBits(uint32_t value,uint32_t op,uint32_t bits)87 int checkBits(uint32_t value, uint32_t op, uint32_t bits)
88 {
89 switch (op)
90 {
91 case CHECK_EQ:
92 if (value == bits)
93 return RULE_MATCH;
94 break;
95 case CHECK_ALL:
96 if ((bits & value) == value)
97 return RULE_MATCH;
98 break;
99 case CHECK_ATLEASTONE:
100 if ((bits & value) != 0)
101 return RULE_MATCH;
102 break;
103 case CHECK_NONE:
104 if ((bits & value) == 0)
105 return RULE_MATCH;
106 break;
107 }
108 return RULE_NOMATCH;
109 }
110
checkOptions(uint32_t value,int op,IPOptions options[],int numOptions)111 int checkOptions(uint32_t value, int op, IPOptions options[], int numOptions)
112 {
113 int found = 0;
114 int i;
115
116 for (i=0;i<numOptions;i++)
117 {
118 if (options[i].option_code == value)
119 {
120 found = 1;
121 break;
122 }
123 }
124
125 switch (op)
126 {
127 case CHECK_EQ:
128 if (found)
129 return RULE_MATCH;
130 else
131 return RULE_NOMATCH;
132 break;
133 case CHECK_NEQ:
134 if (found)
135 return RULE_NOMATCH;
136 else
137 return RULE_MATCH;
138 break;
139 default: /* Should never get here! */
140 break;
141 }
142
143 return RULE_NOMATCH;
144 }
145
checkField(int op,uint32_t value1,uint32_t value2)146 int checkField(int op, uint32_t value1, uint32_t value2)
147 {
148 switch (op)
149 {
150 case CHECK_EQ:
151 if (value1 == value2)
152 return RULE_MATCH;
153 break;
154 case CHECK_NEQ:
155 if (value1 != value2)
156 return RULE_MATCH;
157 break;
158 case CHECK_LT:
159 if (value1 < value2)
160 return RULE_MATCH;
161 break;
162 case CHECK_GT:
163 if (value1 > value2)
164 return RULE_MATCH;
165 break;
166 case CHECK_LTE:
167 if (value1 <= value2)
168 return RULE_MATCH;
169 break;
170 case CHECK_GTE:
171 if (value1 >= value2)
172 return RULE_MATCH;
173 break;
174 case CHECK_AND:
175 if (value1 & value2)
176 return RULE_MATCH;
177 break;
178 case CHECK_XOR:
179 if (value1 ^ value2)
180 return RULE_MATCH;
181 break;
182 }
183
184 return RULE_NOMATCH;
185 }
186
checkHdrOpt(void * p,HdrOptCheck * optData)187 ENGINE_LINKAGE int checkHdrOpt(void *p, HdrOptCheck *optData)
188 {
189 if (optData->flags & NOT_FLAG)
190 return invertMatchResult(checkHdrOptInternal(p, optData));
191 return checkHdrOptInternal(p, optData);
192 }
193
194 /* Exported C source routines */
195 /*
196 * Check header option specified against packet
197 *
198 * Return 1 if check is true (e.g. data matches)
199 * Return 0 if check is not true.
200 */
checkHdrOptInternal(void * p,HdrOptCheck * optData)201 static int checkHdrOptInternal(void *p, HdrOptCheck *optData)
202 {
203 SFSnortPacket *pkt = (SFSnortPacket *)p;
204 /* Header field will be extracted from its native
205 * 1 or 2 bytes, converted to host byte order,
206 * and placed in a 4 byte value for easy comparison
207 */
208 uint32_t value = 0;
209
210 if ((optData->hdrField & IP_HDR_OPTCHECK_MASK) && (!pkt->ip4_header))
211 return RULE_NOMATCH;
212
213 if ((optData->hdrField & TCP_HDR_OPTCHECK_MASK) &&
214 (!pkt->ip4_header || !pkt->tcp_header))
215 return RULE_NOMATCH;
216
217 if ((optData->hdrField & ICMP_HDR_OPTCHECK_MASK) &&
218 (!IPH_IS_VALID(pkt) || !pkt->icmp_header))
219 return RULE_NOMATCH;
220
221 switch (optData->hdrField)
222 {
223 /* IP Header Checks */
224 case IP_HDR_ID:
225 value = IS_IP6(pkt) ? ntohl(GET_IPH_ID(pkt)) : ntohs((uint16_t)GET_IPH_ID(pkt));
226 break;
227 case IP_HDR_PROTO:
228 //value = pkt->ip4_header->proto;
229 value = GET_IPH_PROTO(pkt);
230 break;
231 case IP_HDR_FRAGBITS:
232 return checkBits(optData->value, optData->op, ((ntohs(GET_IPH_OFF(pkt)) & 0xe000) & ~optData->mask_value));
233 break;
234 case IP_HDR_FRAGOFFSET:
235 value = ntohs(GET_IPH_OFF((pkt))) & 0x1FFF;
236 break;
237 case IP_HDR_TOS:
238 //value = pkt->ip4_header->type_service;
239 value = GET_IPH_TOS(pkt);
240 break;
241 case IP_HDR_TTL:
242 //value = pkt->ip4_header->time_to_live;
243 value = GET_IPH_TTL(pkt);
244 break;
245 case IP_HDR_OPTIONS:
246 return checkOptions(optData->value, optData->op, pkt->ip_options, pkt->num_ip_options);
247 break;
248
249 /* TCP Header checks */
250 case TCP_HDR_ACK:
251 value = ntohl(pkt->tcp_header->acknowledgement);
252 break;
253 case TCP_HDR_SEQ:
254 value = ntohl(pkt->tcp_header->sequence);
255 break;
256 case TCP_HDR_FLAGS:
257 return checkBits(optData->value, optData->op, (pkt->tcp_header->flags & ~optData->mask_value));
258 break;
259 case TCP_HDR_WIN:
260 value = ntohs(pkt->tcp_header->window);
261 break;
262 case TCP_HDR_OPTIONS:
263 return checkOptions(optData->value, optData->op, pkt->tcp_options, pkt->num_tcp_options);
264 break;
265
266 /* ICMP Header checks */
267 case ICMP_HDR_CODE:
268 value = pkt->icmp_header->code;
269 break;
270 case ICMP_HDR_TYPE:
271 value = pkt->icmp_header->type;
272 break;
273 case ICMP_HDR_ID:
274 if ((pkt->icmp_header->code == ICMP_ECHO_REQUEST) ||
275 (pkt->icmp_header->code == ICMP_ECHO_REPLY))
276 {
277 value = ntohs(pkt->icmp_header->icmp_header_union.echo.id);
278 }
279 else
280 {
281 return RULE_NOMATCH;
282 }
283 break;
284 case ICMP_HDR_SEQ:
285 if ((pkt->icmp_header->code == ICMP_ECHO_REQUEST) ||
286 (pkt->icmp_header->code == ICMP_ECHO_REPLY))
287 {
288 value = ntohs(pkt->icmp_header->icmp_header_union.echo.seq);
289 }
290 else
291 {
292 return RULE_NOMATCH;
293 }
294 break;
295
296 default:
297 return RULE_NOMATCH;
298 break;
299 }
300
301 return checkField(optData->op, value, optData->value);
302 }
303
304