From 398ba31111fb1c439e6ade1c291e49745b3df646 Mon Sep 17 00:00:00 2001 From: Matias Date: Fri, 12 Aug 2011 21:17:44 -0300 Subject: [PATCH] UDP PDU is now working. --- include/ip.h | 2 +- include/pdu.h | 7 +++++-- include/tcp.h | 11 ++++++----- include/udp.h | 38 +++++++++++++++++++++++++++++++++++++- src/ip.cpp | 2 +- src/pdu.cpp | 30 +++++++++++++++++++++++++++++- src/tcp.cpp | 36 +++++------------------------------- src/udp.cpp | 39 +++++++++++++++++++++++++++++++++++++-- 8 files changed, 121 insertions(+), 44 deletions(-) diff --git a/include/ip.h b/include/ip.h index 3646c81..3bc2f3f 100644 --- a/include/ip.h +++ b/include/ip.h @@ -164,7 +164,7 @@ namespace Tins { static const uint8_t DEFAULT_TTL; void init_ip_fields(); - void write_serialization(uint8_t *buffer, uint32_t total_sz, PDU *parent); + void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); iphdr _ip; std::vector _ip_options; diff --git a/include/pdu.h b/include/pdu.h index 12fae71..508a4be 100644 --- a/include/pdu.h +++ b/include/pdu.h @@ -108,7 +108,7 @@ namespace Tins { virtual bool send(PacketSender* sender) { return false; } protected: /* Serialize this PDU storing the result in buffer. */ - void serialize(uint8_t *buffer, uint32_t total_sz, PDU *parent); + void serialize(uint8_t *buffer, uint32_t total_sz, const PDU *parent); /** \brief Serialices this TCP PDU. * @@ -118,7 +118,10 @@ namespace Tins { * \param total_sz The size available in the buffer. * \param parent The PDU that's one level below this one on the stack. Might be 0. */ - virtual void write_serialization(uint8_t *buffer, uint32_t total_sz, PDU *parent) = 0; + virtual void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) = 0; + + static uint32_t do_checksum(uint8_t *start, uint8_t *end); + static uint32_t pseudoheader_checksum(uint32_t source_ip, uint32_t dest_ip, uint32_t len, uint32_t flag); private: uint32_t _flag; PDU *_inner_pdu; diff --git a/include/tcp.h b/include/tcp.h index 7286c4c..37607c1 100644 --- a/include/tcp.h +++ b/include/tcp.h @@ -111,6 +111,10 @@ namespace Tins { */ inline uint16_t urg_ptr() const { return _tcp.urg_ptr; } + /** \brief Returns the payload. + */ + inline const uint8_t *payload() const { return _payload; } + /** \brief Set the destination port. * \param new_dport New destination port. */ @@ -183,7 +187,7 @@ namespace Tins { /** \brief Returns the header size. * * This metod overrides PDU::header_size. This size includes the - * payload and options size. + * payload and options size. \sa PDU::header_size */ uint32_t header_size() const; private: @@ -239,10 +243,7 @@ namespace Tins { * \param total_sz The size available in the buffer. * \param parent The PDU that's one level below this one on the stack. */ - void write_serialization(uint8_t *buffer, uint32_t total_sz, PDU *parent); - - uint32_t do_checksum(uint8_t *start, uint8_t *end) const; - uint32_t pseudoheader_checksum(uint32_t source_ip, uint32_t dest_ip) const; + void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); tcphdr _tcp; std::vector _options; diff --git a/include/udp.h b/include/udp.h index 6918029..ba74263 100644 --- a/include/udp.h +++ b/include/udp.h @@ -22,6 +22,31 @@ namespace Tins { * */ UDP(uint16_t sport = 0, uint16_t dport = 0); + + /** \brief Returns the payload. + */ + inline const uint8_t *payload() const { return _payload; } + + /** \brief Returns the destination port + */ + inline uint16_t dport() const { return _udp.dport; } + + /** \brief Returns the source port + */ + inline uint16_t sport() const { return _udp.sport; } + + /** \brief Set the destination port. + * + * \param new_dport The new destination port. + */ + void dport(uint16_t new_dport); + + /** \brief Set the source port. + * + * \param new_sport The new source port. + */ + void sport(uint16_t new_sport); + /** \brief Set the payload. * * Payload is NOT copied. Therefore, pointers provided as @@ -30,6 +55,14 @@ namespace Tins { * \param new_payload_size New payload's size */ void payload(uint8_t *new_payload, uint32_t new_payload_size); + + /* Virtual methods */ + /** \brief Returns the header size. + * + * This metod overrides PDU::header_size. This size includes the + * payload and options size. \sa PDU::header_size + */ + uint32_t header_size() const; private: struct udphdr { uint16_t sport; @@ -38,8 +71,11 @@ namespace Tins { uint16_t check; } __attribute__((packed)); + void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); + udphdr _udp; - uint8_t *payload; + uint8_t *_payload; + uint32_t _payload_size; }; }; diff --git a/src/ip.cpp b/src/ip.cpp index 8fc38b0..a59c08c 100644 --- a/src/ip.cpp +++ b/src/ip.cpp @@ -165,7 +165,7 @@ bool Tins::IP::send(PacketSender* sender) { return sender->send_l3(this, (const struct sockaddr*)&link_addr, sizeof(link_addr)); } -void Tins::IP::write_serialization(uint8_t *buffer, uint32_t total_sz, PDU *) { +void Tins::IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) { uint32_t my_sz = header_size(); uint32_t new_flag; assert(total_sz >= my_sz); diff --git a/src/pdu.cpp b/src/pdu.cpp index e770fc6..e1accf0 100644 --- a/src/pdu.cpp +++ b/src/pdu.cpp @@ -20,8 +20,10 @@ */ #include +#include "utils.h" #include "pdu.h" + Tins::PDU::PDU(uint32_t flag, PDU *next_pdu) : _flag(flag), _inner_pdu(next_pdu) { } @@ -56,7 +58,7 @@ uint8_t *Tins::PDU::serialize(uint32_t &sz) { return buffer; } -void Tins::PDU::serialize(uint8_t *buffer, uint32_t total_sz, PDU *parent) { +void Tins::PDU::serialize(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { uint32_t sz = header_size() + trailer_size(); /* Must not happen... */ assert(total_sz >= sz); @@ -65,3 +67,29 @@ void Tins::PDU::serialize(uint8_t *buffer, uint32_t total_sz, PDU *parent) { write_serialization(buffer, total_sz, parent); } +/* Static methods */ +uint32_t Tins::PDU::do_checksum(uint8_t *start, uint8_t *end) { + uint32_t checksum(0); + uint16_t *ptr = (uint16_t*)start, *last = (uint16_t*)end, padding(0); + if(((end - start) & 1) == 1) { + last = (uint16_t*)end - 1; + padding = *(end - 1) << 8; + } + while(ptr < last) + checksum += Utils::net_to_host_s(*(ptr++)); + return checksum + padding; +} + +uint32_t Tins::PDU::pseudoheader_checksum(uint32_t source_ip, uint32_t dest_ip, uint32_t len, uint32_t flag) { + uint32_t checksum(0); + source_ip = Utils::net_to_host_l(source_ip); + dest_ip = Utils::net_to_host_l(dest_ip); + uint16_t *ptr = (uint16_t*)&source_ip; + + checksum += *ptr + ptr[1]; + ptr = (uint16_t*)&dest_ip; + checksum += *ptr + ptr[1]; + checksum += flag + len; + return checksum; +} + diff --git a/src/tcp.cpp b/src/tcp.cpp index e9a41f3..9555944 100644 --- a/src/tcp.cpp +++ b/src/tcp.cpp @@ -128,36 +128,11 @@ void Tins::TCP::add_option(Options tcp_option, uint8_t length, uint8_t *data) { _total_options_size = (padding) ? _options_size - padding + 4 : _options_size; } -uint32_t Tins::TCP::do_checksum(uint8_t *start, uint8_t *end) const { - uint32_t checksum(0); - uint16_t *ptr = (uint16_t*)start, *last = (uint16_t*)end, padding(0); - if(((end - start) & 1) == 1) { - last = (uint16_t*)end - 1; - padding = *(end - 1) << 8; - } - while(ptr < last) - checksum += Utils::net_to_host_s(*(ptr++)); - return checksum + padding; -} - -uint32_t Tins::TCP::pseudoheader_checksum(uint32_t source_ip, uint32_t dest_ip) const { - uint32_t checksum(0), len(header_size()); - source_ip = Utils::net_to_host_l(source_ip); - dest_ip = Utils::net_to_host_l(dest_ip); - uint16_t *ptr = (uint16_t*)&source_ip; - - checksum += *ptr + ptr[1]; - ptr = (uint16_t*)&dest_ip; - checksum += *ptr + ptr[1]; - checksum += IPPROTO_TCP + len; - return checksum; -} - uint32_t Tins::TCP::header_size() const { return sizeof(tcphdr) + _payload_size + _total_options_size; } -void Tins::TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, PDU *parent) { +void Tins::TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { assert(total_sz >= header_size()); uint8_t *tcp_start = buffer; buffer += sizeof(tcphdr); @@ -175,11 +150,10 @@ void Tins::TCP::write_serialization(uint8_t *buffer, uint32_t total_sz, PDU *par memcpy(buffer, _payload, _payload_size); buffer += _payload_size; - IP *ip_packet = dynamic_cast(parent); - if(ip_packet) { - _tcp.check = 0; - uint32_t checksum = pseudoheader_checksum(ip_packet->source_address(), ip_packet->dest_address()) + - do_checksum(tcp_start + sizeof(tcphdr), buffer) + do_checksum((uint8_t*)&_tcp, ((uint8_t*)&_tcp) + sizeof(tcphdr)); + const IP *ip_packet = dynamic_cast(parent); + if(!_tcp.check && ip_packet) { + uint32_t checksum = PDU::pseudoheader_checksum(ip_packet->source_address(), ip_packet->dest_address(), header_size(), IPPROTO_TCP) + + PDU::do_checksum(tcp_start + sizeof(tcphdr), buffer) + PDU::do_checksum((uint8_t*)&_tcp, ((uint8_t*)&_tcp) + sizeof(tcphdr)); while (checksum >> 16) checksum = (checksum & 0xffff)+(checksum >> 16); _tcp.check = Utils::net_to_host_s(~checksum); diff --git a/src/udp.cpp b/src/udp.cpp index e634811..40535d0 100644 --- a/src/udp.cpp +++ b/src/udp.cpp @@ -1,14 +1,49 @@ #ifndef WIN32 #include #endif +#include +#include +#include "utils.h" #include "udp.h" +#include "ip.h" -Tins::UDP::UDP(uint16_t sport, uint16_t dport) : PDU(IPPROTO_UDP), _payload(0) { +Tins::UDP::UDP(uint16_t sport, uint16_t dport) : PDU(IPPROTO_UDP), _payload(0), _payload_size(0) { _udp.sport = sport; _udp.dport = dport; + _udp.check = 0; + _udp.len = 0; } void Tins::UDP::payload(uint8_t *new_payload, uint32_t new_payload_size) { _payload = new_payload; - _udp.len = sizeof(udphdr) + new_payload_size; + _payload_size = new_payload_size; + _udp.len = Utils::net_to_host_s(sizeof(udphdr) + _payload_size); } + +void Tins::UDP::dport(uint16_t new_dport) { + _udp.dport = new_dport; +} + +void Tins::UDP::sport(uint16_t new_sport) { + _udp.sport = new_sport; +} + +uint32_t Tins::UDP::header_size() const { + /* Round? */ + return sizeof(udphdr) + _payload_size; +} + +void Tins::UDP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) { + assert(total_sz >= sizeof(udphdr) + _payload_size); + const IP *ip_packet = dynamic_cast(parent); + if(!_udp.check && ip_packet) { + uint32_t checksum = PDU::pseudoheader_checksum(ip_packet->source_address(), ip_packet->dest_address(), header_size(), IPPROTO_UDP) + + PDU::do_checksum(_payload, _payload + _payload_size) + PDU::do_checksum((uint8_t*)&_udp, ((uint8_t*)&_udp) + sizeof(udphdr)); + while (checksum >> 16) + checksum = (checksum & 0xffff)+(checksum >> 16); + _udp.check = Utils::net_to_host_s(~checksum); + } + std::memcpy(buffer, &_udp, sizeof(udphdr)); + std::memcpy(buffer + sizeof(udphdr), _payload, _payload_size); +} +