diff --git a/include/tcp.h b/include/tcp.h index 99cd572..c091a66 100644 --- a/include/tcp.h +++ b/include/tcp.h @@ -368,6 +368,8 @@ namespace Tins { static const uint16_t DEFAULT_WINDOW; void copy_fields(const TCP *other); + + void cleanup(); /** \brief Serialices this TCP PDU. * \param buffer The buffer in which the PDU will be serialized. * \param total_sz The size available in the buffer. diff --git a/src/tcp.cpp b/src/tcp.cpp index 355812b..c17a580 100644 --- a/src/tcp.cpp +++ b/src/tcp.cpp @@ -56,48 +56,58 @@ Tins::TCP::TCP(const uint8_t *buffer, uint32_t total_sz) : PDU(IPPROTO_TCP) { if(total_sz < sizeof(tcphdr)) throw std::runtime_error("Not enough size for an TCP header in the buffer."); std::memcpy(&_tcp, buffer, sizeof(tcphdr)); - - buffer += sizeof(tcphdr); - total_sz -= sizeof(tcphdr); - - _total_options_size = 0; - _options_size = 0; - - uint32_t index = 0, header_end = (data_offset() * sizeof(uint32_t)) - sizeof(tcphdr); - if(total_sz >= header_end) { - uint8_t args[2] = {0}; - while(index < header_end) { - for(unsigned i(0); i < 2 && args[0] != NOP; ++i) { - args[i] = buffer[index++]; - if(index == header_end) - throw std::runtime_error("Not enought size for a TCP header in the buffer."); - } - // We don't want to store NOPs and EOLs - if(args[0] != NOP && args[0] != EOL) { - args[1] -= (sizeof(uint8_t) << 1); - if(args[1]) { - // Not enough size for this option - if(header_end - index < args[1]) + try { + buffer += sizeof(tcphdr); + total_sz -= sizeof(tcphdr); + + _total_options_size = 0; + _options_size = 0; + + uint32_t index = 0, header_end = (data_offset() * sizeof(uint32_t)) - sizeof(tcphdr); + if(total_sz >= header_end) { + uint8_t args[2] = {0}; + while(index < header_end) { + for(unsigned i(0); i < 2 && args[0] != NOP; ++i) { + args[i] = buffer[index++]; + if(index == header_end) throw std::runtime_error("Not enought size for a TCP header in the buffer."); - add_option((Options)args[0], args[1], buffer + index); } - index += args[1]; + // We don't want to store NOPs and EOLs + if(args[0] != NOP && args[0] != EOL) { + args[1] -= (sizeof(uint8_t) << 1); + if(args[1]) { + // Not enough size for this option + if(header_end - index < args[1]) + throw std::runtime_error("Not enought size for a TCP header in the buffer."); + add_option((Options)args[0], args[1], buffer + index); + } + index += args[1]; + } + else if(args[0] == EOL) + index = header_end; + else // Skip the NOP + args[0] = 0; } - else if(args[0] == EOL) - index = header_end; - else // Skip the NOP - args[0] = 0; + buffer += index; + total_sz -= index; } - buffer += index; - total_sz -= index; + } + catch(std::runtime_error &err) { + cleanup(); + throw; } if(total_sz) inner_pdu(new RawPDU(buffer, total_sz)); } Tins::TCP::~TCP() { + cleanup(); +} + +void Tins::TCP::cleanup() { for(std::list::iterator it = _options.begin(); it != _options.end(); ++it) delete[] it->data; + _options.clear(); } void Tins::TCP::dport(uint16_t new_dport) { @@ -242,8 +252,8 @@ void Tins::TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PD const Tins::IP *ip_packet = dynamic_cast(parent); memcpy(tcp_start, &_tcp, sizeof(tcphdr)); if(!_tcp.check && ip_packet) { - uint32_t checksum = PDU::pseudoheader_checksum(ip_packet->src_addr(), ip_packet->dst_addr(), size(), IPPROTO_TCP) + - PDU::do_checksum(tcp_start, tcp_start + total_sz); + uint32_t checksum = Utils::pseudoheader_checksum(ip_packet->src_addr(), ip_packet->dst_addr(), size(), IPPROTO_TCP) + + Utils::do_checksum(tcp_start, tcp_start + total_sz); while (checksum >> 16) checksum = (checksum & 0xffff) + (checksum >> 16); ((tcphdr*)tcp_start)->check = Utils::net_to_host_s(~checksum);