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