1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +01:00

Fixed memory leak on TCP's options.

This commit is contained in:
Matias Fontanini
2011-09-07 09:52:23 -03:00
parent 201d4b5daf
commit a216cf8401
2 changed files with 44 additions and 32 deletions

View File

@@ -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.

View File

@@ -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<TCPOption>::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<const Tins::IP*>(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);