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_tcp.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 "framework/codec.h"
00027 #include "log/log.h"
00028 #include "log/log_text.h"
00029 #include "main/snort_config.h"
00030 #include "parser/parse_ip.h"
00031 #include "protocols/tcp.h"
00032 #include "protocols/tcp_options.h"
00033 #include "sfip/sf_ipvar.h"
00034 #include "utils/util.h"
00035
00036 #include "checksum.h"
00037
00038 #define CD_TCP_NAME "tcp"
00039 #define CD_TCP_HELP "support for transmission control protocol"
00040
00041 #ifdef WORDS_BIGENDIAN
00042 const uint32_t naptha_seq = 0x005c7b2a;
00043 const uint16_t naptha_id = 0x019d;
00044 #else
00045 const uint32_t naptha_seq = 0x2a7b5c00;
00046 const uint16_t naptha_id = 0x9d01;
00047 #endif
00048
00049 using namespace tcp;
00050
00051 namespace
00052 {
00053 const PegInfo pegs[]
00054 {
00055 { CountType::SUM, "bad_tcp4_checksum", "nonzero tcp over ip checksums" },
00056 { CountType::SUM, "bad_tcp6_checksum", "nonzero tcp over ipv6 checksums" },
00057 { CountType::END, nullptr, nullptr }
00058 };
00059
00060 struct Stats
00061 {
00062 PegCount bad_ip4_cksum;
00063 PegCount bad_ip6_cksum;
00064 };
00065
00066 static THREAD_LOCAL Stats stats;
00067
00068 static const RuleMap tcp_rules[] =
00069 {
00070 { DECODE_TCP_DGRAM_LT_TCPHDR, "TCP packet length is smaller than 20 bytes" },
00071 { DECODE_TCP_INVALID_OFFSET, "TCP data offset is less than 5" },
00072 { DECODE_TCP_LARGE_OFFSET, "TCP header length exceeds packet length" },
00073 { DECODE_TCPOPT_BADLEN, "TCP options found with bad lengths" },
00074 { DECODE_TCPOPT_TRUNCATED, "truncated TCP options" },
00075 { DECODE_TCPOPT_TTCP, "T/TCP detected" },
00076 { DECODE_TCPOPT_OBSOLETE, "obsolete TCP options found" },
00077 { DECODE_TCPOPT_EXPERIMENTAL, "experimental TCP options found" },
00078 { DECODE_TCPOPT_WSCALE_INVALID, "TCP window scale option found with length > 14" },
00079 { DECODE_TCP_XMAS, "XMAS attack detected" },
00080 { DECODE_TCP_NMAP_XMAS, "Nmap XMAS attack detected" },
00081 { DECODE_TCP_BAD_URP, "TCP urgent pointer exceeds payload length or no payload" },
00082 { DECODE_TCP_SYN_FIN, "TCP SYN with FIN" },
00083 { DECODE_TCP_SYN_RST, "TCP SYN with RST" },
00084 { DECODE_TCP_MUST_ACK, "TCP PDU missing ack for established session" },
00085 { DECODE_TCP_NO_SYN_ACK_RST, "TCP has no SYN, ACK, or RST" },
00086 { DECODE_TCP_SHAFT_SYNFLOOD, "DDOS shaft SYN flood" },
00087 { DECODE_TCP_PORT_ZERO, "TCP port 0 traffic" },
00088 { DECODE_DOS_NAPTHA, "DOS NAPTHA vulnerability detected" },
00089 { DECODE_SYN_TO_MULTICAST, "SYN to multicast address" },
00090 { 0, nullptr }
00091 };
00092
00093 class TcpModule : public CodecModule
00094 {
00095 public:
00096 TcpModule() : CodecModule(CD_TCP_NAME, CD_TCP_HELP) { }
00097
00098 const RuleMap* get_rules() const override
00099 { return tcp_rules; }
00100
00101 const PegInfo* get_pegs() const override
00102 { return pegs; }
00103
00104 PegCount* get_counts() const override
00105 { return (PegCount*)&stats; }
00106 };
00107
00108 class TcpCodec : public Codec
00109 {
00110 public:
00111 TcpCodec() : Codec(CD_TCP_NAME)
00112 {
00113 }
00114
00115
00116 void get_protocol_ids(std::vector<ProtocolId>& v) override;
00117 void log(TextLog* const, const uint8_t* pkt, const uint16_t len) override;
00118 bool decode(const RawData&, CodecData&, DecodeData&) override;
00119 bool encode(const uint8_t* const raw_in, const uint16_t raw_len,
00120 EncState&, Buffer&, Flow*) override;
00121 void update(const ip::IpApi&, const EncodeFlags, uint8_t* raw_pkt,
00122 uint16_t lyr_len, uint32_t& updated_len) override;
00123 void format(bool reverse, uint8_t* raw_pkt, DecodeData& snort) override;
00124
00125 private:
00126
00127 int OptLenValidate(const tcp::TcpOption* const opt,
00128 const uint8_t* const end,
00129 const int expected_len);
00130
00131 void DecodeTCPOptions(const uint8_t*, uint32_t, CodecData&);
00132 void TCPMiscTests(const tcp::TCPHdr* const tcph,
00133 const DecodeData& snort,
00134 const CodecData& codec);
00135 };
00136
00137 static sfip_var_t* SynToMulticastDstIp = nullptr;
00138 } // namespace
00139
00140 void TcpCodec::get_protocol_ids(std::vector<ProtocolId>& v)
00141 {
00142 v.push_back(ProtocolId::TCP);
00143 }
00144
00145 bool TcpCodec::decode(const RawData& raw, CodecData& codec, DecodeData& snort)
00146 {
00147 if (raw.len < tcp::TCP_MIN_HEADER_LEN)
00148 {
00149 codec_event(codec, DECODE_TCP_DGRAM_LT_TCPHDR);
00150 return false;
00151 }
00152
00153 /* lay TCP on top of the data cause there is enough of it! */
00154 const tcp::TCPHdr* tcph = reinterpret_cast<const tcp::TCPHdr*>(raw.data);
00155 const uint16_t tcph_len = tcph->hlen();
00156
00157 if (tcph_len < tcp::TCP_MIN_HEADER_LEN)
00158 {
00159 codec_event(codec, DECODE_TCP_INVALID_OFFSET);
00160 return false;
00161 }
00162
00163 if (tcph_len > raw.len)
00164 {
00165 codec_event(codec, DECODE_TCP_LARGE_OFFSET);
00166 return false;
00167 }
00168
00169 /* Checksum code moved in front of the other decoder alerts.
00170 If it's a bad checksum (maybe due to encrypted ESP traffic), the other
00171 alerts could be false positives. */
00172 if ( SnortConfig::tcp_checksums() )
00173 {
00174 uint16_t csum;
00175 PegCount* bad_cksum_cnt;
00176
00177 if (snort.ip_api.is_ip4())
00178 {
00179 bad_cksum_cnt = &(stats.bad_ip4_cksum);
00180 checksum::Pseudoheader ph;
00181 const ip::IP4Hdr* ip4h = snort.ip_api.get_ip4h();
00182 ph.sip = ip4h->get_src();
00183 ph.dip = ip4h->get_dst();
00184 /* setup the pseudo header for checksum calculation */
00185 ph.zero = 0;
00186 ph.protocol = ip4h->proto();
00187 ph.len = htons((uint16_t)raw.len);
00188
00189 /* if we're being "stateless" we probably don't care about the TCP
00190 * checksum, but it's not bad to keep around for shits and giggles */
00191 /* calculate the checksum */
00192 csum = checksum::tcp_cksum((const uint16_t*)(tcph), raw.len, &ph);
00193 }
00194 /* IPv6 traffic */
00195 else
00196 {
00197 bad_cksum_cnt = &(stats.bad_ip4_cksum);
00198 checksum::Pseudoheader6 ph6;
00199 const ip::IP6Hdr* const ip6h = snort.ip_api.get_ip6h();
00200 COPY4(ph6.sip, ip6h->get_src()->u6_addr32);
00201 COPY4(ph6.dip, ip6h->get_dst()->u6_addr32);
00202 ph6.zero = 0;
00203 ph6.protocol = codec.ip6_csum_proto;
00204 ph6.len = htons((uint16_t)raw.len);
00205
00206 csum = checksum::tcp_cksum((const uint16_t*)(tcph), raw.len, &ph6);
00207 }
00208
00209 if (csum && !codec.is_cooked())
00210 {
00211 if ( !(codec.codec_flags & CODEC_UNSURE_ENCAP) )
00212 {
00213 (*bad_cksum_cnt)++;
00214 snort.decode_flags |= DECODE_ERR_CKSUM_TCP;
00215 }
00216 return false;
00217 }
00218 }
00219
00220 if (tcph->are_flags_set(TH_FIN|TH_PUSH|TH_URG))
00221 {
00222 if (tcph->are_flags_set(TH_SYN|TH_ACK|TH_RST))
00223 codec_event(codec, DECODE_TCP_XMAS);
00224 else
00225 codec_event(codec, DECODE_TCP_NMAP_XMAS);
00226
00227 // Allowing this packet for further processing
00228 // (in case there is a valid data inside it).
00229 /* return;*/
00230 }
00231
00232 if (tcph->are_flags_set(TH_SYN))
00233 {
00234 /* check if only SYN is set */
00235 if ( tcph->th_flags == TH_SYN )
00236 {
00237 if ((tcph->th_seq == naptha_seq) and (snort.ip_api.get_ip4h()->ip_id == naptha_id))
00238 {
00239 codec_event(codec, DECODE_DOS_NAPTHA);
00240 }
00241 }
00242
00243 if ( sfvar_ip_in(SynToMulticastDstIp, snort.ip_api.get_dst()) )
00244 codec_event(codec, DECODE_SYN_TO_MULTICAST);
00245
00246 if ( (tcph->th_flags & TH_RST) )
00247 codec_event(codec, DECODE_TCP_SYN_RST);
00248
00249 if ( (tcph->th_flags & TH_FIN) )
00250 codec_event(codec, DECODE_TCP_SYN_FIN);
00251 }
00252 else
00253 { // we already know there is no SYN
00254 if ( !(tcph->th_flags & (TH_ACK|TH_RST)) )
00255 codec_event(codec, DECODE_TCP_NO_SYN_ACK_RST);
00256 }
00257
00258 if ( (tcph->th_flags & (TH_FIN|TH_PUSH|TH_URG)) &&
00259 !(tcph->th_flags & TH_ACK) )
00260 codec_event(codec, DECODE_TCP_MUST_ACK);
00261
00262 /* if options are present, decode them */
00263 uint16_t tcp_opt_len = (uint16_t)(tcph->hlen() - tcp::TCP_MIN_HEADER_LEN);
00264
00265 if (tcp_opt_len > 0)
00266 DecodeTCPOptions((const uint8_t*)(raw.data + tcp::TCP_MIN_HEADER_LEN), tcp_opt_len, codec);
00267
00268 int dsize = raw.len - tcph->hlen();
00269 if (dsize < 0)
00270 dsize = 0;
00271
00272 if ( (tcph->th_flags & TH_URG) &&
00273 ((dsize == 0) || tcph->urp() > dsize) )
00274 codec_event(codec, DECODE_TCP_BAD_URP);
00275
00276 // Now that we are returning true, set the tcp header
00277 codec.lyr_len = tcph_len - codec.invalid_bytes; // set in DecodeTCPOptions()
00278 codec.proto_bits |= PROTO_BIT__TCP;
00279 snort.tcph = tcph;
00280 snort.sp = tcph->src_port();
00281 snort.dp = tcph->dst_port();
00282 snort.set_pkt_type(PktType::TCP);
00283
00284 TCPMiscTests(tcph, snort, codec);
00285
00286 return true;
00287 }
00288
00289 /*
00290 * Function: DecodeTCPOptions()
00291 *
00292 * Purpose: Fairly self explainatory name, don't you think?
00293 *
00294 * TCP Option Header length validation is left to the caller
00295 *
00296 * For a good listing of TCP Options,
00297 * http://www.iana.org/assignments/tcp-parameters
00298 *
00299 * ------------------------------------------------------------
00300 * From: "Kastenholz, Frank" <FKastenholz@unispherenetworks.com>
00301 * Subject: Re: skeeter & bubba TCP options?
00302 *
00303 * ah, the sins of ones youth that never seem to be lost...
00304 *
00305 * it was something that ben levy and stev and i did at ftp many
00306 * many moons ago. bridgham and stev were the instigators of it.
00307 * the idea was simple, put a dh key exchange directly in tcp
00308 * so that all tcp sessions could be encrypted without requiring
00309 * any significant key management system. authentication was not
00310 * a part of the idea, it was to be provided by passwords or
00311 * whatever, which could now be transmitted over the internet
00312 * with impunity since they were encrypted... we implemented
00313 * a simple form of this (doing the math was non trivial on the
00314 * machines of the day). it worked. the only failure that i
00315 * remember was that it was vulnerable to man-in-the-middle
00316 * attacks.
00317 *
00318 * why "skeeter" and "bubba"? well, that's known only to stev...
00319 * ------------------------------------------------------------
00320 *
00321 * 4.2.2.5 TCP Options: RFC-793 Section 3.1
00322 *
00323 * A TCP MUST be able to receive a TCP option in any segment. A TCP
00324 * MUST ignore without error any TCP option it does not implement,
00325 * assuming that the option has a length field (all TCP options
00326 * defined in the future will have length fields). TCP MUST be
00327 * prepared to handle an illegal option length (e.g., zero) without
00328 * crashing; a suggested procedure is to reset the connection and log
00329 * the reason.
00330 *
00331 * Arguments: o_list => ptr to the option list
00332 * o_len => length of the option list
00333 * p => pointer to decoded packet struct
00334 *
00335 * Returns: void function
00336 */
00337 void TcpCodec::DecodeTCPOptions(const uint8_t* start, uint32_t o_len, CodecData& codec)
00338 {
00339 const uint8_t* const end_ptr = start + o_len; /* points to byte after last option */
00340 const tcp::TcpOption* opt = reinterpret_cast<const tcp::TcpOption*>(start);
00341 int code = 2;
00342 uint16_t tot_len = 0;
00343 bool done = false; /* have we reached TCPOPT_EOL yet?*/
00344 bool experimental_option_found = false; /* are all options RFC compliant? */
00345 bool obsolete_option_found = false;
00346
00347 /* Here's what we're doing so that when we find out what these
00348 * other buggers of TCP option codes are, we can do something
00349 * useful
00350 *
00351 * 1) get option code
00352 * 2) check for enough space for current option code
00353 * 4) increment option code ptr
00354 *
00355 * TCP_OPTLENMAX = 40 because of
00356 * (((2^4) - 1) * 4 - tcp::TCP_MIN_HEADER_LEN
00357 *
00358 */
00359
00360 while ((tot_len < o_len) && !done)
00361 {
00362 switch (opt->code)
00363 {
00364 case tcp::TcpOptCode::EOL:
00365 done = true;
00366 codec.invalid_bytes = o_len - tot_len;
00367 /* fallthrough */
00368 case tcp::TcpOptCode::NOP:
00369 code = 0;
00370 break;
00371
00372 case tcp::TcpOptCode::MAXSEG:
00373 code = OptLenValidate(opt, end_ptr, TCPOLEN_MAXSEG);
00374 break;
00375
00376 case tcp::TcpOptCode::SACKOK:
00377 code = OptLenValidate(opt, end_ptr, TCPOLEN_SACKOK);
00378 break;
00379
00380 case tcp::TcpOptCode::WSCALE:
00381 code = OptLenValidate(opt, end_ptr, TCPOLEN_WSCALE);
00382 if (code == 0)
00383 {
00384 if (((uint16_t)opt->data[0] > 14))
00385 {
00386 /* LOG INVALID WINDOWSCALE alert */
00387 codec_event(codec, DECODE_TCPOPT_WSCALE_INVALID);
00388 }
00389 }
00390 break;
00391
00392 case tcp::TcpOptCode::ECHO: /* both use the same lengths */
00393 case tcp::TcpOptCode::ECHOREPLY:
00394 obsolete_option_found = true;
00395 code = OptLenValidate(opt, end_ptr, TCPOLEN_ECHO);
00396 break;
00397
00398 case tcp::TcpOptCode::MD5SIG:
00399 /* RFC 5925 obsoletes this option (see below) */
00400 obsolete_option_found = true;
00401 code = OptLenValidate(opt, end_ptr, TCPOLEN_MD5SIG);
00402 break;
00403
00404 case tcp::TcpOptCode::AUTH:
00405 code = OptLenValidate(opt, end_ptr, -1);
00406
00407 /* Has to have at least 4 bytes - see RFC 5925, Section 2.2 */
00408 if (code >= 0 && opt->len < 4)
00409 code = tcp::OPT_BADLEN;
00410 break;
00411
00412 case tcp::TcpOptCode::SACK:
00413 code = OptLenValidate(opt, end_ptr, -1);
00414
00415 if ((code >= 0) && (opt->len < 2))
00416 code = tcp::OPT_BADLEN;
00417 break;
00418
00419 case tcp::TcpOptCode::CC_ECHO:
00420 codec_event(codec, DECODE_TCPOPT_TTCP);
00421 /* fall through */
00422 case tcp::TcpOptCode::CC: /* all 3 use the same lengths / T/TCP */
00423 case tcp::TcpOptCode::CC_NEW:
00424 code = OptLenValidate(opt, end_ptr, TCPOLEN_CC);
00425 break;
00426
00427 case tcp::TcpOptCode::TRAILER_CSUM:
00428 experimental_option_found = true;
00429 code = OptLenValidate(opt, end_ptr, TCPOLEN_TRAILER_CSUM);
00430 break;
00431
00432 case tcp::TcpOptCode::TIMESTAMP:
00433 code = OptLenValidate(opt, end_ptr, TCPOLEN_TIMESTAMP);
00434 break;
00435
00436 case tcp::TcpOptCode::SKEETER:
00437 case tcp::TcpOptCode::BUBBA:
00438 case tcp::TcpOptCode::UNASSIGNED:
00439 obsolete_option_found = true;
00440 code = OptLenValidate(opt, end_ptr, -1);
00441 break;
00442
00443 case tcp::TcpOptCode::SCPS:
00444 case tcp::TcpOptCode::SELNEGACK:
00445 case tcp::TcpOptCode::RECORDBOUND:
00446 case tcp::TcpOptCode::CORRUPTION:
00447 case tcp::TcpOptCode::PARTIAL_PERM:
00448 case tcp::TcpOptCode::PARTIAL_SVC:
00449 case tcp::TcpOptCode::ALTCSUM:
00450 case tcp::TcpOptCode::SNAP:
00451 default:
00452 experimental_option_found = true;
00453 code = OptLenValidate(opt, end_ptr, -1);
00454 break;
00455 }
00456
00457 if (code < 0)
00458 {
00459 if (code == tcp::OPT_BADLEN)
00460 {
00461 codec_event(codec, DECODE_TCPOPT_BADLEN);
00462 }
00463 else if (code == tcp::OPT_TRUNC)
00464 {
00465 codec_event(codec, DECODE_TCPOPT_TRUNCATED);
00466 }
00467
00468 /* set the option count to the number of valid
00469 * options found before this bad one
00470 * some implementations (BSD and Linux) ignore
00471 * the bad ones, but accept the good ones */
00472 codec.invalid_bytes = o_len - tot_len;
00473 return;
00474 }
00475
00476 tot_len += ((uint8_t)opt->code <= 1) ? 1 : opt->len;
00477 opt = &(opt->next());
00478 }
00479
00480 if (experimental_option_found)
00481 codec_event(codec, DECODE_TCPOPT_EXPERIMENTAL);
00482
00483 else if (obsolete_option_found)
00484 codec_event(codec, DECODE_TCPOPT_OBSOLETE);
00485 }
00486
00487 int TcpCodec::OptLenValidate(const tcp::TcpOption* const opt,
00488 const uint8_t* const end,
00489 const int expected_len)
00490 {
00491 // case for pointer arithmetic
00492 const uint8_t* const opt_ptr = reinterpret_cast<const uint8_t*>(opt);
00493
00494 if (expected_len > 1)
00495 {
00496 /* not enough data to read in a perfect world */
00497 if ((opt_ptr + expected_len) > end)
00498 return tcp::OPT_TRUNC;
00499
00500 if (opt->len != expected_len)
00501 return tcp::OPT_BADLEN;
00502 }
00503 else /* expected_len < 0 (i.e. variable length) */
00504 {
00505 /* RFC says that we MUST have at least this much data */
00506 if (opt->len < 2)
00507 return tcp::OPT_BADLEN;
00508
00509 /* not enough data to read in a perfect world */
00510 if ((opt_ptr + opt->len) > end)
00511 return tcp::OPT_TRUNC;
00512 }
00513
00514 return 0;
00515 }
00516
00517 /* TCP-layer decoder alerts */
00518 void TcpCodec::TCPMiscTests(const tcp::TCPHdr* const tcph,
00519 const DecodeData& snort,
00520 const CodecData& codec)
00521 {
00522 if ( ((tcph->th_flags & TH_NORESERVED) == TH_SYN ) &&
00523 (tcph->seq() == 674711609) )
00524 codec_event(codec, DECODE_TCP_SHAFT_SYNFLOOD);
00525
00526 if (snort.sp == 0 || snort.dp == 0)
00527 codec_event(codec, DECODE_TCP_PORT_ZERO);
00528 }
00529
00530 /******************************************************************
00531 ************************ L O G G E R **************************
00532 ******************************************************************/
00533
00534 void TcpCodec::log(TextLog* const text_log, const uint8_t* raw_pkt,
00535 const uint16_t lyr_len)
00536 {
00537 char tcpFlags[9];
00538
00539 const tcp::TCPHdr* const tcph = reinterpret_cast<const tcp::TCPHdr*>(raw_pkt);
00540
00541 /* print TCP flags */
00542 CreateTCPFlagString(tcph, tcpFlags);
00543 TextLog_Puts(text_log, tcpFlags); /* We don't care about the NULL */
00544
00545 /* print other TCP info */
00546 TextLog_Print(text_log, " SrcPort:%u DstPort:%u\n\tSeq: 0x%lX Ack: 0x%lX "
00547 "Win: 0x%X TcpLen: %d",ntohs(tcph->th_sport),
00548 ntohs(tcph->th_dport), (u_long)ntohl(tcph->th_seq),
00549 (u_long)ntohl(tcph->th_ack),
00550 ntohs(tcph->th_win), tcph->off());
00551
00552 if ((tcph->th_flags & TH_URG) != 0)
00553 TextLog_Print(text_log, "UrgPtr: 0x%X", tcph->urp());
00554
00555 /* dump the TCP options */
00556 if (tcph->has_options())
00557 {
00558 TextLog_Puts(text_log, "\n\t");
00559 LogTcpOptions(text_log, tcph, lyr_len);
00560 }
00561 }
00562
00563 /******************************************************************
00564 ************************* E N C O D E R *************************
00565 ******************************************************************/
00566
00567 //-------------------------------------------------------------------------
00568 // TCP
00569 // encoder creates TCP RST
00570 // should always try to use acceptable ack since we send RSTs in a
00571 // stateless fashion ... from rfc 793:
00572 //
00573 // In all states except SYN-SENT, all reset (RST) segments are validated
00574 // by checking their SEQ-fields. A reset is valid if its sequence number
00575 // is in the window. In the SYN-SENT state (a RST received in response
00576 // to an initial SYN), the RST is acceptable if the ACK field
00577 // acknowledges the SYN.
00578 //-------------------------------------------------------------------------
00579
00580 bool TcpCodec::encode(const uint8_t* const raw_in, const uint16_t /*raw_len*/,
00581 EncState& enc, Buffer& buf, Flow*)
00582 {
00583 const tcp::TCPHdr* const hi = reinterpret_cast<const tcp::TCPHdr*>(raw_in);
00584
00585 if (!buf.allocate(tcp::TCP_MIN_HEADER_LEN))
00586 return false;
00587
00588 tcp::TCPHdr* tcph_out = reinterpret_cast<tcp::TCPHdr*>(buf.data());
00589 const int ctl = (hi->th_flags & TH_SYN) ? 1 : 0;
00590
00591 if ( enc.forward() )
00592 {
00593 tcph_out->th_sport = hi->th_sport;
00594 tcph_out->th_dport = hi->th_dport;
00595
00596 // th_seq depends on whether the data passes or drops
00597 if (enc.flags & ENC_FLAG_INLINE)
00598 tcph_out->th_seq = hi->th_seq;
00599 else
00600 tcph_out->th_seq = htonl(ntohl(hi->th_seq) + enc.dsize + ctl);
00601
00602 tcph_out->th_ack = hi->th_ack;
00603 }
00604 else
00605 {
00606 tcph_out->th_sport = hi->th_dport;
00607 tcph_out->th_dport = hi->th_sport;
00608
00609 tcph_out->th_seq = hi->th_ack;
00610 tcph_out->th_ack = htonl(ntohl(hi->th_seq) + enc.dsize + ctl);
00611 }
00612
00613 if ( enc.flags & ENC_FLAG_SEQ )
00614 {
00615 uint32_t seq = ntohl(tcph_out->th_seq);
00616 seq += (enc.flags & ENC_FLAG_VAL);
00617 tcph_out->th_seq = htonl(seq);
00618 }
00619
00620 tcph_out->th_offx2 = 0;
00621 tcph_out->set_offset(tcp::TCP_MIN_HEADER_LEN >> 2);
00622 tcph_out->th_win = 0;
00623 tcph_out->th_urp = 0;
00624
00625 if ( (enc.flags & (ENC_FLAG_PSH | ENC_FLAG_FIN)) )
00626 {
00627 tcph_out->th_flags = TH_ACK;
00628 if ( enc.flags & ENC_FLAG_PSH )
00629 {
00630 tcph_out->th_flags |= TH_PUSH;
00631 tcph_out->th_win = htons(65535);
00632 }
00633 else
00634 {
00635 tcph_out->th_flags |= TH_FIN;
00636 }
00637 }
00638 else
00639 {
00640 tcph_out->th_flags = TH_RST | TH_ACK;
00641 }
00642
00643 // in case of ip6 extension headers, this gets next correct
00644 enc.next_proto = IpProtocol::TCP;
00645 tcph_out->th_sum = 0;
00646 const ip::IpApi& ip_api = enc.ip_api;
00647
00648 if (ip_api.is_ip4())
00649 {
00650 checksum::Pseudoheader ps;
00651 int len = buf.size();
00652
00653 const IP4Hdr* const ip4h = ip_api.get_ip4h();
00654 ps.sip = ip4h->get_src();
00655 ps.dip = ip4h->get_dst();
00656 ps.zero = 0;
00657 ps.protocol = IpProtocol::TCP;
00658 ps.len = htons((uint16_t)len);
00659 tcph_out->th_sum = checksum::tcp_cksum((uint16_t*)tcph_out, len, &ps);
00660 }
00661 else if (ip_api.is_ip6())
00662 {
00663 checksum::Pseudoheader6 ps6;
00664 int len = buf.size();
00665
00666 const ip::IP6Hdr* const ip6h = ip_api.get_ip6h();
00667 memcpy(&ps6.sip, ip6h->get_src()->u6_addr8, sizeof(ps6.sip));
00668 memcpy(&ps6.dip, ip6h->get_dst()->u6_addr8, sizeof(ps6.dip));
00669 ps6.zero = 0;
00670 ps6.protocol = IpProtocol::TCP;
00671 ps6.len = htons((uint16_t)len);
00672 tcph_out->th_sum = checksum::tcp_cksum((uint16_t*)tcph_out, len, &ps6);
00673 }
00674
00675 return true;
00676 }
00677
00678 void TcpCodec::update(const ip::IpApi& api, const EncodeFlags flags, uint8_t* raw_pkt,
00679 uint16_t /*lyr_len*/, uint32_t& updated_len)
00680 {
00681 tcp::TCPHdr* const h = reinterpret_cast<tcp::TCPHdr*>(raw_pkt);
00682
00683 updated_len += h->hlen();
00684
00685 if ( !(flags & UPD_COOKED) || (flags & UPD_REBUILT_FRAG) )
00686 {
00687 h->th_sum = 0;
00688
00689 if ( api.is_ip4() )
00690 {
00691 checksum::Pseudoheader ps;
00692 const ip::IP4Hdr* const ip4h = api.get_ip4h();
00693 ps.sip = ip4h->get_src();
00694 ps.dip = ip4h->get_dst();
00695 ps.zero = 0;
00696 ps.protocol = IpProtocol::TCP;
00697 ps.len = htons((uint16_t)updated_len);
00698 h->th_sum = checksum::tcp_cksum((uint16_t*)h, updated_len, &ps);
00699 }
00700 else
00701 {
00702 checksum::Pseudoheader6 ps6;
00703 const ip::IP6Hdr* const ip6h = api.get_ip6h();
00704 memcpy(ps6.sip, ip6h->get_src()->u6_addr32, sizeof(ps6.sip));
00705 memcpy(ps6.dip, ip6h->get_dst()->u6_addr32, sizeof(ps6.dip));
00706 ps6.zero = 0;
00707 ps6.protocol = IpProtocol::TCP;
00708 ps6.len = htons((uint16_t)updated_len);
00709 h->th_sum = checksum::tcp_cksum((uint16_t*)h, updated_len, &ps6);
00710 }
00711 }
00712 }
00713
00714 void TcpCodec::format(bool reverse, uint8_t* raw_pkt, DecodeData& snort)
00715 {
00716 tcp::TCPHdr* tcph = reinterpret_cast<tcp::TCPHdr*>(raw_pkt);
00717
00718 if ( reverse )
00719 {
00720 uint16_t tmp_port = tcph->th_sport;
00721 tcph->th_sport = tcph->th_dport;
00722 tcph->th_dport = tmp_port;
00723 }
00724
00725 snort.tcph = tcph;
00726 snort.sp = tcph->src_port();
00727 snort.dp = tcph->dst_port();
00728 snort.set_pkt_type(PktType::TCP);
00729 }
00730
00731 //-------------------------------------------------------------------------
00732 // api
00733 //-------------------------------------------------------------------------
00734
00735 static Module* mod_ctor()
00736 { return new TcpModule; }
00737
00738 static void mod_dtor(Module* m)
00739 { delete m; }
00740
00741 /*
00742 * Static api functions. there are NOT part of the TCPCodec class,
00743 * but provide global initializers and/or destructors to the class
00744 */
00745
00746 static void tcp_codec_ginit()
00747 {
00748 // Multicast addresses pursuant to RFC 5771
00749 SynToMulticastDstIp = sfip_var_from_string("[224.0.0.0/4]");
00750 assert(SynToMulticastDstIp);
00751 }
00752
00753 static void tcp_codec_gterm()
00754 {
00755 if ( SynToMulticastDstIp )
00756 sfvar_free(SynToMulticastDstIp);
00757 }
00758
00759 static Codec* ctor(Module*)
00760 { return new TcpCodec(); }
00761
00762 static void dtor(Codec* cd)
00763 { delete cd; }
00764
00765 static const CodecApi tcp_api =
00766 {
00767 {
00768 PT_CODEC,
00769 sizeof(CodecApi),
00770 CDAPI_VERSION,
00771 0,
00772 API_RESERVED,
00773 API_OPTIONS,
00774 CD_TCP_NAME,
00775 CD_TCP_HELP,
00776 mod_ctor,
00777 mod_dtor,
00778 },
00779 tcp_codec_ginit, // pinit
00780 tcp_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_tcp[] =
00791 //#endif
00792 {
00793 &tcp_api.base,
00794 nullptr
00795 };
00796
END OF CODE