00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 // Copyright (C) 2002-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 // cd_ipv4.cc author Josh Rosenbaum <jrosenba@cisco.com>
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024
00025 #include "codecs/codec_module.h"
00026 #include "log/log_text.h"
00027 #include "log/messages.h"
00028 #include "main/snort_config.h"
00029 #include "packet_io/active.h"
00030 #include "parser/parse_ip.h"
00031 #include "protocols/ip.h"
00032 #include "protocols/ipv4.h"
00033 #include "protocols/ipv4_options.h"
00034 #include "protocols/tcp.h"
00035 #include "sfip/sf_ipvar.h"
00036 #include "utils/dnet_header.h"
00037
00038 #include "checksum.h"
00039
00040 #define CD_IPV4_NAME "ipv4"
00041 #define CD_IPV4_HELP "support for Internet protocol v4"
00042
00043 namespace
00044 {
00045 const PegInfo pegs[]
00046 {
00047 { CountType::SUM, "bad_checksum", "nonzero ip checksums" },
00048 { CountType::END, nullptr, nullptr }
00049 };
00050
00051 struct Stats
00052 {
00053 PegCount bad_cksum;
00054 };
00055
00056 static THREAD_LOCAL Stats stats;
00057 static sfip_var_t* MulticastReservedIp = nullptr;
00058
00059 static const RuleMap ipv4_rules[] =
00060 {
00061 { DECODE_NOT_IPV4_DGRAM, "not IPv4 datagram" },
00062 { DECODE_IPV4_INVALID_HEADER_LEN, "IPv4 header length < minimum" },
00063 { DECODE_IPV4_DGRAM_LT_IPHDR, "IPv4 datagram length < header field" },
00064 { DECODE_IPV4OPT_BADLEN, "IPv4 options found with bad lengths" },
00065 { DECODE_IPV4OPT_TRUNCATED, "truncated IPv4 options" },
00066 { DECODE_IPV4_DGRAM_GT_CAPLEN, "IPv4 datagram length > captured length" },
00067 { DECODE_ZERO_TTL, "IPv4 packet with zero TTL" },
00068 { DECODE_BAD_FRAGBITS, "IPv4 packet with bad frag bits (both MF and DF set)" },
00069 { DECODE_IP4_LEN_OFFSET, "IPv4 packet frag offset + length exceed maximum" },
00070 { DECODE_IP4_SRC_THIS_NET, "IPv4 packet from 'current net' source address" },
00071 { DECODE_IP4_DST_THIS_NET, "IPv4 packet to 'current net' dest address" },
00072 { DECODE_IP4_SRC_MULTICAST, "IPv4 packet from multicast source address" },
00073 { DECODE_IP4_SRC_RESERVED, "IPv4 packet from reserved source address" },
00074 { DECODE_IP4_DST_RESERVED, "IPv4 packet to reserved dest address" },
00075 { DECODE_IP4_SRC_BROADCAST, "IPv4 packet from broadcast source address" },
00076 { DECODE_IP4_DST_BROADCAST, "IPv4 packet to broadcast dest address" },
00077 { DECODE_IP4_MIN_TTL, "IPv4 packet below TTL limit" },
00078 { DECODE_IP4_DF_OFFSET, "IPv4 packet both DF and offset set" },
00079 { DECODE_IP_RESERVED_FRAG_BIT, "IPv4 reserved bit set" },
00080 { DECODE_IP_OPTION_SET, "IPv4 option set" },
00081 { DECODE_IP4_HDR_TRUNC, "truncated IPv4 header" },
00082 { 0, nullptr }
00083 };
00084
00085 class Ipv4Module : public CodecModule
00086 {
00087 public:
00088 Ipv4Module() : CodecModule(CD_IPV4_NAME, CD_IPV4_HELP) { }
00089
00090 const RuleMap* get_rules() const override
00091 { return ipv4_rules; }
00092
00093 const PegInfo* get_pegs() const override
00094 { return pegs; }
00095
00096 PegCount* get_counts() const override
00097 { return (PegCount*)&stats; }
00098 };
00099
00100 class Ipv4Codec : public Codec
00101 {
00102 public:
00103 Ipv4Codec() : Codec(CD_IPV4_NAME) { }
00104
00105 void get_protocol_ids(std::vector<ProtocolId>& v) override;
00106 bool decode(const RawData&, CodecData&, DecodeData&) override;
00107 void log(TextLog* const, const uint8_t* pkt, const uint16_t len) override;
00108 bool encode(const uint8_t* const raw_in, const uint16_t raw_len,
00109 EncState&, Buffer&, Flow*) override;
00110 void update(const ip::IpApi&, const EncodeFlags, uint8_t* raw_pkt,
00111 uint16_t lyr_len, uint32_t& updated_len) override;
00112 void format(bool reverse, uint8_t* raw_pkt, DecodeData& snort) override;
00113
00114 private:
00115 void IP4AddrTests(const IP4Hdr*, const CodecData&, DecodeData&);
00116 void IPMiscTests(const IP4Hdr* const ip4h, const CodecData& codec, uint16_t len);
00117 void DecodeIPOptions(const uint8_t* start, uint8_t& o_len, CodecData& data);
00118 };
00119
00120 const uint16_t IP_ID_COUNT = 8192;
00121 static THREAD_LOCAL rand_t* s_rand = nullptr;
00122 static THREAD_LOCAL uint16_t s_id_index = 0;
00123 static THREAD_LOCAL std::array<uint16_t, IP_ID_COUNT> s_id_pool {
00124 { 0 }
00125 };
00126 } // namespace
00127
00128 void Ipv4Codec::get_protocol_ids(std::vector<ProtocolId>& v)
00129 {
00130 v.push_back(ProtocolId::ETHERTYPE_IPV4);
00131 v.push_back(ProtocolId::IPIP);
00132 }
00133
00134 bool Ipv4Codec::decode(const RawData& raw, CodecData& codec, DecodeData& snort)
00135 {
00136 uint32_t ip_len; /* length from the start of the ip hdr to the pkt end */
00137 uint16_t hlen; /* ip header length */
00138
00139 if (raw.len < ip::IP4_HEADER_LEN)
00140 {
00141 if ((codec.codec_flags & CODEC_UNSURE_ENCAP) == 0)
00142 codec_event(codec, DECODE_IP4_HDR_TRUNC);
00143 return false;
00144 }
00145
00146 if ( snort_conf->hit_ip_maxlayers(codec.ip_layer_cnt) )
00147 {
00148 codec_event(codec, DECODE_IP_MULTIPLE_ENCAPSULATION);
00149 return false;
00150 }
00151
00152 ++codec.ip_layer_cnt;
00153 /* lay the IP struct over the raw data */
00154 const IP4Hdr* const iph = reinterpret_cast<const IP4Hdr*>(raw.data);
00155
00156 /*
00157 * with datalink DLT_RAW it's impossible to differ ARP datagrams from IP.
00158 * So we are just ignoring non IP datagrams
00159 */
00160 if (iph->ver() != 4)
00161 {
00162 if ((codec.codec_flags & CODEC_UNSURE_ENCAP) == 0)
00163 codec_event(codec, DECODE_NOT_IPV4_DGRAM);
00164 return false;
00165 }
00166
00167 ip_len = iph->len();
00168 hlen = iph->hlen();
00169
00170 if (hlen < ip::IP4_HEADER_LEN)
00171 {
00172 DebugFormat(DEBUG_DECODE,
00173 "Bogus IP header length of %i bytes\n", hlen);
00174
00175 codec_event(codec, DECODE_IPV4_INVALID_HEADER_LEN);
00176 return false;
00177 }
00178
00179 if (ip_len > raw.len)
00180 {
00181 DebugFormat(DEBUG_DECODE,
00182 "IP Len field is %u bytes bigger than captured length.\n"
00183 " (ip.len: %u, cap.len: %u)\n",
00184 ip_len - raw.len, ip_len, raw.len);
00185
00186 codec_event(codec, DECODE_IPV4_DGRAM_GT_CAPLEN);
00187 // FIXIT-L we should decode this layer if possible instead of stopping now
00188 // ip6 etc may have similar issues
00189 return false;
00190 }
00191 #if 0
00192 else if (ip_len < len)
00193 {
00194 // There is no need to alert when (ip_len < len).
00195 // Libpcap will capture more bytes than are part of the IP payload.
00196 // These could be Ethernet trailers, ESP trailers, etc.
00197 }
00198 #endif
00199
00200 if (ip_len < hlen)
00201 {
00202 DebugFormat(DEBUG_DECODE,
00203 "IP dgm len (%u bytes) < IP hdr "
00204 "len (%hu bytes), packet discarded\n", ip_len, hlen);
00205
00206 codec_event(codec, DECODE_IPV4_DGRAM_LT_IPHDR);
00207 return false;
00208 }
00209
00210 if ( snort.ip_api.is_ip6() )
00211 {
00212 /* If Teredo or GRE seen, this is not an 4in6 tunnel */
00213 if ( codec.codec_flags & CODEC_NON_IP_TUNNEL )
00214 codec.codec_flags &= ~CODEC_NON_IP_TUNNEL;
00215 else if ( SnortConfig::tunnel_bypass_enabled(TUNNEL_4IN6) )
00216 Active::set_tunnel_bypass();
00217 }
00218 else if (snort.ip_api.is_ip4())
00219 {
00220 /* If Teredo or GRE seen, this is not an 4in4 tunnel */
00221 if ( codec.codec_flags & CODEC_NON_IP_TUNNEL )
00222 codec.codec_flags &= ~CODEC_NON_IP_TUNNEL;
00223 else if (SnortConfig::tunnel_bypass_enabled(TUNNEL_4IN4))
00224 Active::set_tunnel_bypass();
00225 }
00226
00227 // set the api now since this layer has been verified as valid
00228 snort.ip_api.set(iph);
00229
00230 /*
00231 * IP Header tests: Land attack, and Loop back test
00232 */
00233 IP4AddrTests(iph, codec, snort);
00234
00235 if (SnortConfig::ip_checksums())
00236 {
00237 /* routers drop packets with bad IP checksums, we don't really
00238 * need to check them (should make this a command line/config
00239 * option
00240 */
00241 int16_t csum = checksum::ip_cksum((const uint16_t*)iph, hlen);
00242
00243 if (csum && !codec.is_cooked())
00244 {
00245 if ( !(codec.codec_flags & CODEC_UNSURE_ENCAP) )
00246 {
00247 stats.bad_cksum++;
00248 snort.decode_flags |= DECODE_ERR_CKSUM_IP;
00249 }
00250 return false;
00251 }
00252 }
00253
00254 /* test for IP options */
00255 codec.codec_flags &= ~(CODEC_IPOPT_FLAGS);
00256 uint8_t ip_opt_len = (uint8_t)(hlen - ip::IP4_HEADER_LEN);
00257
00258 if (ip_opt_len > 0)
00259 DecodeIPOptions((raw.data + ip::IP4_HEADER_LEN), ip_opt_len, codec);
00260
00261 /* set the remaining packet length */
00262 const_cast<uint32_t&>(raw.len) = ip_len;
00263 ip_len -= hlen;
00264
00265 /* check for fragmented packets */
00266 uint16_t frag_off = iph->off_w_flags();
00267
00268 /*
00269 * get the values of the reserved, more
00270 * fragments and don't fragment flags
00271 */
00272 if (frag_off & 0x8000)
00273 {
00274 codec_event(codec, DECODE_IP_RESERVED_FRAG_BIT);
00275 // data.decode_flags |= DECODE_RF; -- flag never needed
00276 }
00277
00278 if (frag_off & 0x4000)
00279 codec.codec_flags |= CODEC_DF;
00280
00281 if (frag_off & 0x2000)
00282 snort.decode_flags |= DECODE_MF;
00283
00284 /* mask off the high bits in the fragment offset field */
00285 frag_off &= 0x1FFF;
00286
00287 // to get the real frag_off, we need to multiply by 8. However, since
00288 // the actual frag_off is never used, we can comment this out
00289 // frag_off = frag_off << 3;
00290
00291 if ( (codec.codec_flags & CODEC_DF) && frag_off )
00292 codec_event(codec, DECODE_IP4_DF_OFFSET);
00293
00294 if ( frag_off + ip_len > IP_MAXPACKET )
00295 codec_event(codec, DECODE_IP4_LEN_OFFSET);
00296
00297 if ( frag_off || (snort.decode_flags & DECODE_MF))
00298 {
00299 // FIXIT-L identical to DEFRAG_ANOMALY_ZERO
00300 if ( !ip_len)
00301 codec_event(codec, DECODE_ZERO_LENGTH_FRAG);
00302
00303 snort.decode_flags |= DECODE_FRAG;
00304 }
00305 else
00306 {
00307 snort.decode_flags &= ~DECODE_FRAG;
00308 }
00309
00310 if ( (snort.decode_flags & DECODE_MF) && (codec.codec_flags & CODEC_DF))
00311 codec_event(codec, DECODE_BAD_FRAGBITS);
00312
00313 snort.set_pkt_type(PktType::IP);
00314 codec.proto_bits |= PROTO_BIT__IP;
00315 IPMiscTests(iph, codec, ip::IP4_HEADER_LEN + ip_opt_len);
00316
00317 codec.lyr_len = hlen - codec.invalid_bytes;
00318 codec.curr_ip6_extension = 0; // necessary since next protos numbers share
00319 codec.ip6_extension_count = 0; // same space for both ip4 and ip6
00320
00321 /* if this packet isn't a fragment
00322 * or if it is, its a UDP packet and offset is 0 */
00323 if (!(snort.decode_flags & DECODE_FRAG) /*||
00324 ((frag_off == 0) && // FIXIT-H this forces flow to udp instead of ip
00325 (iph->proto() == IpProtocol::UDP))*/)
00326 {
00327 if (to_utype(iph->proto()) >= to_utype(ProtocolId::MIN_UNASSIGNED_IP_PROTO))
00328 codec_event(codec, DECODE_IP_UNASSIGNED_PROTO);
00329 else
00330 codec.next_prot_id = (ProtocolId)iph->proto();
00331 }
00332
00333 return true;
00334 }
00335
00336 void Ipv4Codec::IP4AddrTests(
00337 const IP4Hdr* iph, const CodecData& codec, DecodeData& snort)
00338 {
00339 uint8_t msb_src, msb_dst;
00340
00341 // check all 32 bits ...
00342 if ( iph->ip_src == iph->ip_dst )
00343 {
00344 codec_event(codec, DECODE_BAD_TRAFFIC_SAME_SRCDST);
00345 }
00346
00347 // check all 32 bits ...
00348 if (iph->is_src_broadcast())
00349 codec_event(codec, DECODE_IP4_SRC_BROADCAST);
00350
00351 if (iph->is_dst_broadcast())
00352 codec_event(codec, DECODE_IP4_DST_BROADCAST);
00353
00354 /* Loopback traffic - don't use htonl for speed reasons -
00355 * s_addr is always in network order */
00356 #ifdef WORDS_BIGENDIAN
00357 msb_src = (iph.ip_src >> 24);
00358 msb_dst = (iph.ip_dst >> 24);
00359 #else
00360 msb_src = (uint8_t)(iph->ip_src & 0xff);
00361 msb_dst = (uint8_t)(iph->ip_dst & 0xff);
00362 #endif
00363 // check the msb ...
00364 if ( (msb_src == ip::IP4_LOOPBACK) || (msb_dst == ip::IP4_LOOPBACK) )
00365 {
00366 codec_event(codec, DECODE_BAD_TRAFFIC_LOOPBACK);
00367 }
00368 // check the msb ...
00369 if ( msb_src == ip::IP4_THIS_NET )
00370 codec_event(codec, DECODE_IP4_SRC_THIS_NET);
00371
00372 if ( msb_dst == ip::IP4_THIS_NET )
00373 codec_event(codec, DECODE_IP4_DST_THIS_NET);
00374
00375 // check the 'msn' (most significant nibble) ...
00376 msb_src >>= 4;
00377 msb_dst >>= 4;
00378
00379 if ( msb_src == ip::IP4_MULTICAST )
00380 codec_event(codec, DECODE_IP4_SRC_MULTICAST);
00381
00382 if ( msb_src == ip::IP4_RESERVED || sfvar_ip_in(MulticastReservedIp, snort.ip_api.get_src()) )
00383 codec_event(codec, DECODE_IP4_SRC_RESERVED);
00384
00385 if ( msb_dst == ip::IP4_RESERVED || sfvar_ip_in(MulticastReservedIp, snort.ip_api.get_dst()) )
00386 codec_event(codec, DECODE_IP4_DST_RESERVED);
00387 }
00388
00389 /* IPv4-layer decoder rules */
00390 void Ipv4Codec::IPMiscTests(const IP4Hdr* const ip4h, const CodecData& codec, uint16_t len)
00391 {
00392 /* Yes, it's an ICMP-related vuln in IP options. */
00393 int cnt = 0;
00394
00395 /* Alert on IP packets with either 0x07 (Record Route) or 0x44 (Timestamp)
00396 options that are specially crafted. */
00397 ip::IpOptionIterator iter(ip4h, (uint8_t)(len));
00398 for (const ip::IpOptions& opt : iter)
00399 {
00400 ++cnt;
00401
00402 switch (opt.code)
00403 {
00404 case ip::IPOptionCodes::EOL:
00405 --cnt;
00406 break;
00407
00408 case ip::IPOptionCodes::RR:
00409 {
00410 const uint8_t length = opt.len;
00411 if (length < 3)
00412 continue;
00413
00414 uint8_t pointer = opt.data[0];
00415
00416 /* If the pointer goes past the end of the data, then the data
00417 is full. That's okay. */
00418 if (pointer >= length)
00419 continue;
00420 /* If the remaining space in the option isn't a multiple of 4
00421 bytes, alert. */
00422 if (((length + 1) - pointer) % 4)
00423 codec_event(codec, DECODE_ICMP_DOS_ATTEMPT);
00424
00425 break;
00426 }
00427 case ip::IPOptionCodes::TS:
00428 {
00429 const uint8_t length = opt.get_len();
00430 if (length < 2)
00431 continue;
00432
00433 uint8_t pointer = opt.data[0];
00434
00435 /* If the pointer goes past the end of the data, then the data
00436 is full. That's okay. */
00437 if (pointer >= length)
00438 continue;
00439 /* If the remaining space in the option isn't a multiple of 4
00440 bytes, alert. */
00441 if (((length + 1) - pointer) % 4)
00442 codec_event(codec, DECODE_ICMP_DOS_ATTEMPT);
00443 /* If there is a timestamp + address, we need a multiple of 8
00444 bytes instead. */
00445 if ((opt.data[1] & 0x01) && /* address flag */
00446 (((length + 1) - pointer) % 8))
00447 codec_event(codec, DECODE_ICMP_DOS_ATTEMPT);
00448
00449 break;
00450 }
00451 default:
00452 break;
00453 }
00454 }
00455
00456 if (cnt > 0)
00457 codec_event(codec, DECODE_IP_OPTION_SET);
00458 }
00459
00460 void Ipv4Codec::DecodeIPOptions(const uint8_t* start, uint8_t& o_len, CodecData& codec)
00461 {
00462 uint32_t tot_len = 0;
00463 int code = 0; /* negative error codes are returned from bad options */
00464
00465 const ip::IpOptions* option = reinterpret_cast<const ip::IpOptions*>(start);
00466
00467 while (tot_len < o_len)
00468 {
00469 switch (option->code)
00470 {
00471 case ip::IPOptionCodes::EOL:
00472 /* if we hit an EOL, we're done */
00473 tot_len++;
00474 codec.invalid_bytes = o_len - tot_len;
00475 o_len = tot_len;
00476 return;
00477 // fall through
00478
00479 case ip::IPOptionCodes::NOP:
00480 tot_len++;
00481 break;
00482
00483 case ip::IPOptionCodes::RTRALT:
00484 codec.codec_flags |= CODEC_IPOPT_RTRALT_SEEN;
00485 goto default_case;
00486
00487 case ip::IPOptionCodes::RR:
00488 codec.codec_flags |= CODEC_IPOPT_RR_SEEN;
00489 // fall through
00490
00491 default_case:
00492 default:
00493
00494 if ((tot_len + 1) >= o_len)
00495 code = tcp::OPT_TRUNC;
00496
00497 /* RFC says that we MUST have at least this much data */
00498 else if (option->len < 2)
00499 code = tcp::OPT_BADLEN;
00500
00501 else if (tot_len + option->get_len() > o_len)
00502 /* not enough data to read in a perfect world */
00503 code = tcp::OPT_TRUNC;
00504
00505 else if (option->len == 3)
00506 /* for IGMP alert */
00507 codec.codec_flags |= CODEC_IPOPT_LEN_THREE;
00508
00509 if (code < 0)
00510 {
00511 /* Yes, we use TCP_OPT_* for the IP option decoder. */
00512 if (code == tcp::OPT_BADLEN)
00513 codec_event(codec, DECODE_IPV4OPT_BADLEN);
00514 else if (code == tcp::OPT_TRUNC)
00515 codec_event(codec, DECODE_IPV4OPT_TRUNCATED);
00516
00517 codec.invalid_bytes = o_len - tot_len;
00518 o_len = tot_len;
00519 return;
00520 }
00521
00522 tot_len += option->len;
00523 }
00524
00525 option = &(option->next());
00526 }
00527 }
00528
00529 /******************************************************************
00530 ********************* L O G G E R ******************************
00531 *******************************************************************/
00532
00533 struct ip4_addr
00534 {
00535 union
00536 {
00537 uint32_t addr32;
00538 uint8_t addr8[4];
00539 };
00540 };
00541
00542 void Ipv4Codec::log(TextLog* const text_log, const uint8_t* raw_pkt,
00543 const uint16_t lyr_len)
00544 {
00545 const IP4Hdr* const ip4h = reinterpret_cast<const IP4Hdr*>(raw_pkt);
00546
00547 // FIXIT-H this does NOT obfuscate correctly
00548 if (SnortConfig::obfuscate())
00549 {
00550 TextLog_Print(text_log, "xxx.xxx.xxx.xxx -> xxx.xxx.xxx.xxx");
00551 }
00552 else
00553 {
00554 ip4_addr src, dst;
00555 src.addr32 = ip4h->get_src();
00556 dst.addr32 = ip4h->get_dst();
00557
00558 char src_buf[INET_ADDRSTRLEN];
00559 char dst_buf[INET_ADDRSTRLEN];
00560
00561 inet_ntop(AF_INET, &src, src_buf, sizeof(src_buf));
00562 inet_ntop(AF_INET, &dst, dst_buf, sizeof(dst_buf));
00563
00564 TextLog_Print(text_log, "%s -> %s", src_buf, dst_buf);
00565 }
00566
00567 TextLog_NewLine(text_log);
00568 TextLog_Putc(text_log, '\t');
00569
00570 const uint16_t hlen = ip4h->hlen();
00571 const uint16_t len = ip4h->len();
00572 const uint16_t frag_off = ip4h->off_w_flags();
00573 bool mf_set = false;
00574
00575 TextLog_Print(text_log, "Next:0x%02X TTL:%u TOS:0x%X ID:%u IpLen:%u DgmLen:%u",
00576 ip4h->proto(), ip4h->ttl(), ip4h->tos(),
00577 ip4h->id(), hlen, len);
00578
00579 /* print the reserved bit if it's set */
00580 if (frag_off & 0x8000)
00581 TextLog_Puts(text_log, " RB");
00582
00583 /* printf more frags/don't frag bits */
00584 if (frag_off & 0x4000)
00585 TextLog_Puts(text_log, " DF");
00586
00587 if (frag_off & 0x2000)
00588 {
00589 TextLog_Puts(text_log, " MF");
00590 mf_set = true;
00591 }
00592
00593 /* print IP options */
00594 if (ip4h->has_options())
00595 {
00596 TextLog_Putc(text_log, '\t');
00597 TextLog_NewLine(text_log);
00598 LogIpOptions(text_log, ip4h, lyr_len);
00599 }
00600
00601 if ( mf_set || (frag_off & 0x1FFF) )
00602 {
00603 TextLog_NewLine(text_log);
00604 TextLog_Putc(text_log, '\t');
00605 TextLog_Print(text_log, "Frag Offset: 0x%04X Frag Size: 0x%04X\n",
00606 (frag_off & 0x1FFF) * 8, (len - hlen));
00607 }
00608 }
00609
00610 /******************************************************************
00611 ******************** E N C O D E R ******************************
00612 *******************************************************************/
00613
00614 static inline uint16_t IpId_Next()
00615 {
00616 #if defined(REG_TEST)
00617 uint16_t id = htons(s_id_index + 1);
00618 #else
00619 uint16_t id = s_id_pool[s_id_index];
00620 #endif
00621 s_id_index = (s_id_index + 1) % IP_ID_COUNT;
00622
00623 if ( !s_id_index )
00624 rand_shuffle(s_rand, &s_id_pool[0], sizeof(s_id_pool), 1);
00625
00626 return id;
00627 }
00628
00629 /******************************************************************
00630 ******************** E N C O D E R ******************************
00631 ******************************************************************/
00632 bool Ipv4Codec::encode(const uint8_t* const raw_in, const uint16_t /*raw_len*/,
00633 EncState& enc, Buffer& buf, Flow*)
00634 {
00635 if (!buf.allocate(ip::IP4_HEADER_LEN))
00636 return false;
00637
00638 const ip::IP4Hdr* const ip4h_in = reinterpret_cast<const IP4Hdr*>(raw_in);
00639 ip::IP4Hdr* const ip4h_out = reinterpret_cast<IP4Hdr*>(buf.data());
00640
00641 /* IPv4 encoded header is hardcoded 20 bytes */
00642 ip4h_out->ip_verhl = 0x45;
00643 ip4h_out->ip_off = 0;
00644 ip4h_out->ip_id = IpId_Next();
00645 ip4h_out->ip_tos = ip4h_in->ip_tos;
00646 ip4h_out->ip_proto = ip4h_in->ip_proto;
00647 ip4h_out->ip_len = htons((uint16_t)buf.size());
00648 ip4h_out->ip_csum = 0;
00649
00650 if ( enc.forward() )
00651 {
00652 ip4h_out->ip_src = ip4h_in->ip_src;
00653 ip4h_out->ip_dst = ip4h_in->ip_dst;
00654 ip4h_out->ip_ttl = enc.get_ttl(ip4h_in->ip_ttl);
00655 }
00656 else
00657 {
00658 ip4h_out->ip_src = ip4h_in->ip_dst;
00659 ip4h_out->ip_dst = ip4h_in->ip_src;
00660 ip4h_out->ip_ttl = enc.get_ttl(ip4h_in->ip_ttl);
00661 }
00662
00663 if ( enc.next_proto_set() )
00664 ip4h_out->ip_proto = enc.next_proto;
00665
00666 /* IPv4 encoded header is hardcoded 20 bytes, we save some
00667 * cycles and use the literal header size for checksum */
00668 ip4h_out->ip_csum = checksum::ip_cksum((uint16_t*)ip4h_out, ip::IP4_HEADER_LEN);
00669
00670 enc.next_proto = IpProtocol::IPIP;
00671 enc.next_ethertype = ProtocolId::ETHERTYPE_IPV4;
00672 return true;
00673 }
00674
00675 void Ipv4Codec::update(const ip::IpApi&, const EncodeFlags flags,
00676 uint8_t* raw_pkt, uint16_t /*lyr_len*/, uint32_t& updated_len)
00677 {
00678 IP4Hdr* h = reinterpret_cast<IP4Hdr*>(raw_pkt);
00679 uint16_t hlen = h->hlen();
00680
00681 updated_len += hlen;
00682 h->set_ip_len((uint16_t)updated_len);
00683
00684 if ( !(flags & UPD_COOKED) || (flags & UPD_REBUILT_FRAG) )
00685 {
00686 h->ip_csum = 0;
00687 h->ip_csum = checksum::ip_cksum((uint16_t*)h, hlen);
00688 }
00689 }
00690
00691 void Ipv4Codec::format(bool reverse, uint8_t* raw_pkt, DecodeData& snort)
00692 {
00693 IP4Hdr* ip4h = reinterpret_cast<IP4Hdr*>(raw_pkt);
00694
00695 if ( reverse )
00696 {
00697 uint32_t tmp_ip = ip4h->ip_src;
00698 ip4h->ip_src = ip4h->ip_dst;
00699 ip4h->ip_dst = tmp_ip;
00700 }
00701
00702 snort.ip_api.set(ip4h);
00703 snort.set_pkt_type(PktType::IP);
00704 }
00705
00706 //-------------------------------------------------------------------------
00707 // api
00708 //-------------------------------------------------------------------------
00709
00710 static Module* mod_ctor()
00711 { return new Ipv4Module; }
00712
00713 static void mod_dtor(Module* m)
00714 { delete m; }
00715
00716 //-------------------------------------------------------------------------
00717 // ip id considerations:
00718 //
00719 // we use dnet's rand services to generate a vector of random 16-bit values and
00720 // iterate over the vector as IDs are assigned. when we wrap to the beginning,
00721 // the vector is randomly reordered.
00722 //-------------------------------------------------------------------------
00723 static void ipv4_codec_ginit()
00724 {
00725 if ( s_rand )
00726 rand_close(s_rand);
00727
00728 // rand_open() can yield valgrind errors because the
00729 // starting seed may come from "random stack contents"
00730 // (see man 3 dnet)
00731 s_rand = rand_open();
00732
00733 if ( !s_rand )
00734 FatalError("rand_open() failed.\n");
00735
00736 rand_get(s_rand, &s_id_pool[0], sizeof(s_id_pool));
00737
00738 // Reserved addresses within multicast address space (See RFC 5771)
00739 MulticastReservedIp = sfip_var_from_string(
00740 "[224.1.0.0/16,224.5.0.0/16,224.6.0.0/15,224.8.0.0/13,224.16.0.0/12,"
00741 "224.32.0.0/11,224.64.0.0/10,224.128.0.0/9,225.0.0.0/8,226.0.0.0/7,"
00742 "228.0.0.0/6,234.0.0.0/7,236.0.0.0/7,238.0.0.0/8]");
00743
00744 assert(MulticastReservedIp);
00745 }
00746
00747 static void ipv4_codec_gterm()
00748 {
00749 if ( s_rand )
00750 rand_close(s_rand);
00751
00752 if ( MulticastReservedIp )
00753 sfvar_free(MulticastReservedIp);
00754
00755 s_rand = nullptr;
00756 MulticastReservedIp = nullptr;
00757 }
00758
00759 static Codec* ctor(Module*)
00760 { return new Ipv4Codec; }
00761
00762 static void dtor(Codec* cd)
00763 { delete cd; }
00764
00765 static const CodecApi ipv4_api =
00766 {
00767 {
00768 PT_CODEC,
00769 sizeof(CodecApi),
00770 CDAPI_VERSION,
00771 0,
00772 API_RESERVED,
00773 API_OPTIONS,
00774 CD_IPV4_NAME,
00775 CD_IPV4_HELP,
00776 mod_ctor,
00777 mod_dtor
00778 },
00779 ipv4_codec_ginit, // pinit
00780 ipv4_codec_gterm, // pterm
00781 nullptr, // tinit
00782 nullptr, // tterm
00783 ctor, // ctor
00784 dtor, // dtor
00785 };
00786
00787 #ifdef BUILDING_SO
00788 SO_PUBLIC const BaseApi* snort_plugins[] =
00789 #else
00790 const BaseApi* cd_ipv4[] =
00791 #endif
00792 {
00793 &ipv4_api.base,
00794 nullptr
00795 };
00796
END OF CODE