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