00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 // Copyright (C) 2005-2013 Sourcefire, Inc.
00004 //
00005 // This program is free software; you can redistribute it and/or modify it
00006 // under the terms of the GNU General Public License Version 2 as published
00007 // by the Free Software Foundation. You may not use, modify or distribute
00008 // this program under any other version of the GNU General Public License.
00009 //
00010 // This program is distributed in the hope that it will be useful, but
00011 // WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License along
00016 // with this program; if not, write to the Free Software Foundation, Inc.,
00017 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018 //--------------------------------------------------------------------------
00019 // flow_key.cc author Steven Sturges <ssturges@sourcefire.com>
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024
00025 #include "flow/flow_key.h"
00026
00027 #include "hash/sfhashfcn.h"
00028 #include "main/snort_config.h"
00029 #include "protocols/icmp4.h"
00030 #include "protocols/icmp6.h"
00031 #include "utils/util.h"
00032
00033 //-------------------------------------------------------------------------
00034 // icmp foo
00035 //-------------------------------------------------------------------------
00036
00037 static const ip::snort_in6_addr fixed_addr = { { { 0xFF, 0, 0, 0 } } };
00038
00039 inline void FlowKey::update_icmp4(const SfIp*& srcIP, uint16_t& srcPort,
00040 const SfIp*& dstIP, uint16_t& dstPort)
00041 {
00042 if (srcPort == ICMP_ECHOREPLY)
00043 {
00044 /* Treat ICMP echo reply the same as request */
00045 dstPort = ICMP_ECHO;
00046 srcPort = 0;
00047 }
00048 else if (srcPort == ICMP_ROUTER_ADVERTISE)
00049 {
00050 dstPort = ICMP_ROUTER_SOLICIT; /* Treat ICMP router advertisement the same as solicitation */
00051 srcPort = 0;
00052 srcIP = (SfIp *)&fixed_addr; /* Matching src address to solicit dest address */
00053 }
00054 else
00055 {
00056 /* otherwise, every ICMP type gets different key */
00057 dstPort = 0;
00058 if (srcPort == ICMP_ROUTER_SOLICIT)
00059 dstIP = (SfIp* )&fixed_addr; /* To get unique key, don't use multicast/broadcast addr (RFC 1256) */
00060 }
00061 }
00062
00063 inline void FlowKey::update_icmp6(const SfIp*& srcIP, uint16_t& srcPort,
00064 const SfIp*& dstIP, uint16_t& dstPort)
00065 {
00066 if (srcPort == icmp::Icmp6Types::ECHO_REPLY)
00067 {
00068 /* Treat ICMPv6 echo reply the same as request */
00069 dstPort = icmp::Icmp6Types::ECHO_REQUEST;
00070 srcPort = 0;
00071 }
00072 else if (srcPort == icmp::Icmp6Types::ROUTER_ADVERTISEMENT)
00073 {
00074 dstPort = icmp::Icmp6Types::ROUTER_SOLICITATION; /* Treat ICMPv6 router advertisement the same as solicitation */
00075 srcPort = 0;
00076 srcIP = (SfIp* )&fixed_addr; /* Matching src address to solicit dest address */
00077 }
00078 else
00079 {
00080 /* otherwise, every ICMP type gets different key */
00081 dstPort = 0;
00082 if (srcPort == icmp::Icmp6Types::ROUTER_SOLICITATION)
00083 dstIP = (SfIp* )&fixed_addr; /* To get unique key, don't use multicast addr (RFC 4861) */
00084 }
00085 }
00086
00087 //-------------------------------------------------------------------------
00088 // init foo
00089 //-------------------------------------------------------------------------
00090 inline bool FlowKey::init4(
00091 IpProtocol ip_proto,
00092 const SfIp *srcIP, uint16_t srcPort,
00093 const SfIp *dstIP, uint16_t dstPort,
00094 uint32_t mplsId, bool order)
00095 {
00096 uint32_t src;
00097 uint32_t dst;
00098 bool reversed = false;
00099
00100 if (ip_proto == IpProtocol::ICMPV4)
00101 update_icmp4(srcIP, srcPort, dstIP, dstPort);
00102
00103 src = srcIP->get_ip4_value();
00104 dst = dstIP->get_ip4_value();
00105
00106 /* These comparisons are done in this fashion for performance reasons */
00107 if ( !order || src < dst)
00108 {
00109 COPY4(ip_l, srcIP->get_ip6_ptr());
00110 COPY4(ip_h, dstIP->get_ip6_ptr());
00111 port_l = srcPort;
00112 port_h = dstPort;
00113 }
00114 else if (src == dst)
00115 {
00116 COPY4(ip_l, srcIP->get_ip6_ptr());
00117 COPY4(ip_h, dstIP->get_ip6_ptr());
00118 if (srcPort < dstPort)
00119 {
00120 port_l = srcPort;
00121 port_h = dstPort;
00122 }
00123 else
00124 {
00125 port_l = dstPort;
00126 port_h = srcPort;
00127 reversed = true;
00128 }
00129 }
00130 else
00131 {
00132 COPY4(ip_l, dstIP->get_ip6_ptr());
00133 port_l = dstPort;
00134 COPY4(ip_h, srcIP->get_ip6_ptr());
00135 port_h = srcPort;
00136 reversed = true;
00137 }
00138 if (SnortConfig::mpls_overlapping_ip() &&
00139 ip::isPrivateIP(src) && ip::isPrivateIP(dst))
00140 mplsLabel = mplsId;
00141 else
00142 mplsLabel = 0;
00143
00144 return reversed;
00145 }
00146
00147 inline bool FlowKey::init6(
00148 IpProtocol ip_proto,
00149 const SfIp *srcIP, uint16_t srcPort,
00150 const SfIp *dstIP, uint16_t dstPort,
00151 uint32_t mplsId, bool order)
00152 {
00153 bool reversed = false;
00154
00155 if (ip_proto == IpProtocol::ICMPV6)
00156 update_icmp6(srcIP, srcPort, dstIP, dstPort);
00157 else if (ip_proto == IpProtocol::ICMPV4)
00158 update_icmp4(srcIP, srcPort, dstIP, dstPort);
00159
00160 if ( !order || srcIP->fast_lt6(*dstIP))
00161 {
00162 COPY4(ip_l, srcIP->get_ip6_ptr());
00163 port_l = srcPort;
00164 COPY4(ip_h, dstIP->get_ip6_ptr());
00165 port_h = dstPort;
00166 }
00167 else if (srcIP->fast_eq6(*dstIP))
00168 {
00169 COPY4(ip_l, srcIP->get_ip6_ptr());
00170 COPY4(ip_h, dstIP->get_ip6_ptr());
00171 if (srcPort < dstPort)
00172 {
00173 port_l = srcPort;
00174 port_h = dstPort;
00175 }
00176 else
00177 {
00178 port_l = dstPort;
00179 port_h = srcPort;
00180 reversed = true;
00181 }
00182 }
00183 else
00184 {
00185 COPY4(ip_l, dstIP->get_ip6_ptr());
00186 port_l = dstPort;
00187 COPY4(ip_h, srcIP->get_ip6_ptr());
00188 port_h = srcPort;
00189 reversed = true;
00190 }
00191
00192 if (SnortConfig::mpls_overlapping_ip())
00193 mplsLabel = mplsId;
00194 else
00195 mplsLabel = 0;
00196
00197 return reversed;
00198 }
00199
00200 void FlowKey::init_vlan(uint16_t vlanId)
00201 {
00202 if (!SnortConfig::get_vlan_agnostic())
00203 vlan_tag = vlanId;
00204 else
00205 vlan_tag = 0;
00206 }
00207
00208 void FlowKey::init_address_space(uint16_t addrSpaceId)
00209 {
00210 if (!SnortConfig::address_space_agnostic())
00211 addressSpaceId = addrSpaceId;
00212 else
00213 addressSpaceId = 0;
00214 }
00215
00216 void FlowKey::init_mpls(uint32_t mplsId)
00217 {
00218 if (SnortConfig::mpls_overlapping_ip())
00219 mplsLabel = mplsId;
00220 else
00221 mplsLabel = 0;
00222 }
00223
00224 bool FlowKey::init(
00225 PktType type, IpProtocol ip_proto,
00226 const SfIp *srcIP, uint16_t srcPort,
00227 const SfIp *dstIP, uint16_t dstPort,
00228 uint16_t vlanId, uint32_t mplsId, uint16_t addrSpaceId)
00229 {
00230 bool reversed;
00231
00232 /* Because the key is going to be used for hash lookups,
00233 * the key fields will be normalized such that the lower
00234 * of the IP addresses is stored in ip_l and the port for
00235 * that IP is stored in port_l.
00236 */
00237
00238 if (srcIP->is_ip4())
00239 {
00240 version = 4;
00241 reversed = init4(ip_proto, srcIP, srcPort, dstIP, dstPort, mplsId);
00242 }
00243 else
00244 {
00245 version = 6;
00246 reversed = init6(ip_proto, srcIP, srcPort, dstIP, dstPort, mplsId);
00247 }
00248
00249 pkt_type = type;
00250 ip_protocol = (uint8_t)ip_proto;
00251
00252 init_vlan(vlanId);
00253 init_address_space(addrSpaceId);
00254 padding = 0;
00255
00256 return reversed;
00257 }
00258
00259 bool FlowKey::init(
00260 PktType type, IpProtocol ip_proto,
00261 const SfIp *srcIP, const SfIp *dstIP,
00262 uint32_t id, uint16_t vlanId,
00263 uint32_t mplsId, uint16_t addrSpaceId)
00264 {
00265 // to avoid confusing 2 different datagrams or confusing a datagram
00266 // with a session, we don't order the addresses and we set version
00267 uint16_t srcPort = id & 0xFFFF;
00268 uint16_t dstPort = id >> 16;
00269
00270 if (srcIP->is_ip4())
00271 {
00272 version = 4;
00273 init4(ip_proto, srcIP, srcPort, dstIP, dstPort, mplsId, false);
00274 ip_protocol = (uint8_t)ip_proto;
00275 }
00276 else
00277 {
00278 version = 6;
00279 init6(ip_proto, srcIP, srcPort, dstIP, dstPort, mplsId, false);
00280 ip_protocol = 0;
00281 }
00282
00283 pkt_type = type;
00284
00285 init_vlan(vlanId);
00286 init_address_space(addrSpaceId);
00287 padding = 0;
00288
00289 return false;
00290 }
00291
00292 //-------------------------------------------------------------------------
00293 // hash foo
00294 //-------------------------------------------------------------------------
00295
00296 uint32_t FlowKey::hash(SFHASHFCN* hf, const unsigned char* p, int)
00297 {
00298 uint32_t a, b, c;
00299 a = b = c = hf->hardener;
00300
00301 const uint32_t* d = (const uint32_t*)p;
00302
00303 a += d[0]; // IPv6 lo[0]
00304 b += d[1]; // IPv6 lo[1]
00305 c += d[2]; // IPv6 lo[2]
00306
00307 mix(a, b, c);
00308
00309 a += d[3]; // IPv6 lo[3]
00310 b += d[4]; // IPv6 hi[0]
00311 c += d[5]; // IPv6 hi[1]
00312
00313 mix(a, b, c);
00314
00315 a += d[6]; // IPv6 hi[2]
00316 b += d[7]; // IPv6 hi[3]
00317 c += d[8]; // mpls label
00318
00319 mix(a, b, c);
00320
00321 a += d[9]; // port lo & port hi
00322 b += d[10]; // vlan tag, address space id
00323 c += d[11]; // ip_proto, pkt_type, version, and 8bits of zeroed pad,
00324
00325 finalize(a, b, c);
00326
00327 return c;
00328 }
00329
00330 int FlowKey::compare(const void* s1, const void* s2, size_t)
00331 {
00332 const uint64_t* a,* b;
00333
00334 a = (const uint64_t*)s1;
00335 b = (const uint64_t*)s2;
00336 if (*a - *b)
00337 return 1; /* Compares IPv4 lo/hi
00338 Compares IPv6 low[0,1] */
00339
00340 a++;
00341 b++;
00342 if (*a - *b)
00343 return 1; /* Compares port lo/hi, vlan, protocol, version
00344 Compares IPv6 low[2,3] */
00345
00346 a++;
00347 b++;
00348 if (*a - *b)
00349 return 1; /* Compares IPv6 hi[0,1] */
00350
00351 a++;
00352 b++;
00353 if (*a - *b)
00354 return 1; /* Compares IPv6 hi[2,3] */
00355
00356 a++;
00357 b++;
00358 if (*a - *b)
00359 return 1; /* Compares MPLS label, port lo/hi */
00360
00361 a++;
00362 b++;
00363 if (*a - *b)
00364 return 1; /* Compares vlan,AddressSpace ID,ip_proto,type,version,8 bit pad */
00365
00366 return 0;
00367 }
00368
END OF CODE