1 //--------------------------------------------------------------------------
2 // Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18 // packet_constraints.cc author Serhii Lysenko <selysenk@cisco.com>
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "packet_constraints.h"
25
26 #include "protocols/packet.h"
27
28 #include <cstring>
29
30 namespace {
31
match_constraints(const snort::PacketConstraints & cs,const snort::SfIp & sip,const snort::SfIp & dip,uint16_t sport,uint16_t dport)32 inline bool match_constraints(const snort::PacketConstraints& cs,
33 const snort::SfIp& sip, const snort::SfIp& dip, uint16_t sport,
34 uint16_t dport)
35 {
36 using SetBits = snort::PacketConstraints::SetBits;
37
38 return (!(cs.set_bits & SetBits::SRC_PORT) or (sport == cs.src_port)) and
39 (!(cs.set_bits & SetBits::DST_PORT) or (dport == cs.dst_port)) and
40 (!(cs.set_bits & SetBits::SRC_IP) or (sip == cs.src_ip)) and
41 (!(cs.set_bits & SetBits::DST_IP) or (dip == cs.dst_ip));
42 }
43
44 } // namespace
45
46 using namespace snort;
47
operator ==(const PacketConstraints & other) const48 bool PacketConstraints::operator==(const PacketConstraints& other) const
49 {
50 return set_bits == other.set_bits
51 and ( !(set_bits & IP_PROTO) or ip_proto == other.ip_proto )
52 and ( !(set_bits & SRC_PORT) or src_port == other.src_port )
53 and ( !(set_bits & DST_PORT) or dst_port == other.dst_port )
54 and ( !(set_bits & SRC_IP) or src_ip == other.src_ip )
55 and ( !(set_bits & DST_IP) or dst_ip == other.dst_ip );
56 }
57
packet_match(const Packet & p) const58 bool PacketConstraints::packet_match(const Packet& p) const
59 {
60 if ( !match )
61 return false;
62
63 if ( !p.has_ip() )
64 {
65 if ( set_bits & (SetBits::IP_PROTO|SetBits::SRC_PORT|SetBits::DST_PORT|SetBits::SRC_IP|SetBits::DST_IP) )
66 return false;
67 else
68 return true;
69 }
70
71 if ( (set_bits & SetBits::IP_PROTO) and (p.get_ip_proto_next() != ip_proto) )
72 return false;
73
74 const auto& sip = *p.ptrs.ip_api.get_src();
75 const auto& dip = *p.ptrs.ip_api.get_dst();
76 const auto sp = p.ptrs.sp;
77 const auto dp = p.ptrs.dp;
78
79 return match_constraints(*this, sip, dip, sp, dp) or
80 match_constraints(*this, dip, sip, dp, sp);
81 }
82
flow_match(const Flow & f) const83 bool PacketConstraints::flow_match(const Flow& f) const
84 {
85 if ( !match )
86 return false;
87
88 if ( (set_bits & SetBits::IP_PROTO) and
89 (IpProtocol(f.ip_proto) != ip_proto) )
90 return false;
91
92 return match_constraints(*this, f.client_ip, f.server_ip, f.client_port,
93 f.server_port);
94 }
95
96 #ifdef UNIT_TEST
97
98 #include <catch/snort_catch.h>
99
100 TEST_CASE("Packet constraints comparison", "[framework]")
101 {
102 SECTION("all unset")
103 {
104 const PacketConstraints exp = { IpProtocol::TCP, 10, 20,
105 SfIp(), SfIp(), 0 };
106 const PacketConstraints act = { IpProtocol::UDP, 30, 40,
107 SfIp(), SfIp(), 0 };
108 CHECK( exp == act );
109 }
110
111 SECTION("dst unset")
112 {
113 const uint32_t ip1 = 0x01010101;
114 const uint32_t ip2 = 0x02020202;
115 const PacketConstraints exp = { IpProtocol::PROTO_NOT_SET, 10, 20,
116 SfIp(&ip1, AF_INET), SfIp(&ip2, AF_INET),
117 (uint8_t)~PacketConstraints::SetBits::DST_IP };
118 const PacketConstraints act = { IpProtocol::PROTO_NOT_SET, 10, 20,
119 SfIp(&ip1, AF_INET), SfIp(),
120 (uint8_t)~PacketConstraints::SetBits::DST_IP };
121 CHECK( exp == act );
122 }
123
124 SECTION("not equal")
125 {
126 const uint32_t ip1 = 0x01010101;
127 const uint32_t ip2 = 0x02020202;
128 const uint32_t ip3 = 0x03030303;
129 const PacketConstraints exp = { IpProtocol::PROTO_NOT_SET, 0, 0,
130 SfIp(&ip1, AF_INET), SfIp(&ip2, AF_INET), (uint8_t)-1 };
131 const PacketConstraints act = { IpProtocol::PROTO_NOT_SET, 0, 0,
132 SfIp(&ip3, AF_INET), SfIp(&ip2, AF_INET), (uint8_t)-1};
133 CHECK( !(exp == act) );
134 }
135
136 SECTION("equal")
137 {
138 const uint32_t ip1 = 0x01010101;
139 const uint32_t ip2 = 0x02020202;
140 const PacketConstraints exp = { IpProtocol::PROTO_NOT_SET, 0, 0,
141 SfIp(&ip1, AF_INET), SfIp(&ip2, AF_INET), (uint8_t)-1 };
142 const PacketConstraints act = { IpProtocol::PROTO_NOT_SET, 0, 0,
143 SfIp(&ip1, AF_INET), SfIp(&ip2, AF_INET), (uint8_t)-1 };
144 CHECK( exp == act );
145 }
146 }
147
148 TEST_CASE("Packet constraints matching", "[framework]")
149 {
150 PacketConstraints cs;
151
152 const auto proto = IpProtocol::TCP;
153 const uint16_t sport = 100;
154 const uint16_t dport = 200;
155 snort::SfIp sip, dip;
156 sip.set("10.1.1.1");
157 dip.set("10.1.1.2");
158
159
160 SECTION("full match")
161 {
162 cs.set_bits = PacketConstraints::SetBits::IP_PROTO;
163 cs.set_bits |= PacketConstraints::SetBits::SRC_PORT;
164 cs.set_bits |= PacketConstraints::SetBits::DST_PORT;
165 cs.set_bits |= PacketConstraints::SetBits::SRC_IP;
166 cs.set_bits |= PacketConstraints::SetBits::DST_IP;
167
168 cs.ip_proto = proto;
169 cs.src_port = sport;
170 cs.dst_port = dport;
171 cs.src_ip = sip;
172 cs.dst_ip = dip;
173
174 CHECK( match_constraints(cs, sip, dip, sport, dport) );
175 }
176
177 SECTION("backwards")
178 {
179 cs.set_bits = PacketConstraints::SetBits::IP_PROTO;
180 cs.set_bits |= PacketConstraints::SetBits::SRC_PORT;
181 cs.set_bits |= PacketConstraints::SetBits::DST_PORT;
182 cs.set_bits |= PacketConstraints::SetBits::SRC_IP;
183 cs.set_bits |= PacketConstraints::SetBits::DST_IP;
184
185 cs.ip_proto = proto;
186 cs.src_port = sport;
187 cs.dst_port = dport;
188 cs.src_ip = sip;
189 cs.dst_ip = dip;
190
191 CHECK( !match_constraints(cs, dip, sip, dport, sport) );
192 }
193
194 SECTION("any ip")
195 {
196 cs.set_bits = PacketConstraints::SetBits::IP_PROTO;
197 cs.set_bits |= PacketConstraints::SetBits::SRC_PORT;
198 cs.set_bits |= PacketConstraints::SetBits::DST_PORT;
199
200 cs.ip_proto = proto;
201 cs.src_port = sport;
202 cs.dst_port = dport;
203
204 CHECK( match_constraints(cs, sip, dip, sport, dport) );
205 }
206
207 SECTION("any port")
208 {
209 cs.set_bits = PacketConstraints::SetBits::IP_PROTO;
210 cs.set_bits |= PacketConstraints::SetBits::SRC_IP;
211 cs.set_bits |= PacketConstraints::SetBits::DST_IP;
212
213 cs.ip_proto = proto;
214 cs.src_ip = sip;
215 cs.dst_ip = dip;
216
217 CHECK( match_constraints(cs, sip, dip, sport, dport) );
218 }
219
220 SECTION("any src")
221 {
222 cs.set_bits = PacketConstraints::SetBits::IP_PROTO;
223 cs.set_bits |= PacketConstraints::SetBits::DST_PORT;
224 cs.set_bits |= PacketConstraints::SetBits::DST_IP;
225
226 cs.ip_proto = proto;
227 cs.dst_port = dport;
228 cs.dst_ip = dip;
229
230 CHECK( match_constraints(cs, sip, dip, sport, dport) );
231 }
232 }
233
234 #endif
235
236