Commit decee38f authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[2902] Implemented a function decoding IP and UDP header.

parent 35b62ac9
......@@ -12,17 +12,20 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <asiolink/io_address.h>
#include <dhcp/dhcp6.h> // defines HWTYPE_ETHERNET
#include <dhcp/protocol_util.h>
#include <boost/static_assert.hpp>
#include <netinet/ip.h>
using namespace isc::asiolink;
using namespace isc::util;
namespace isc {
namespace dhcp {
void decodeEthernetHeader(InputBuffer& buf, Pkt4Ptr& pkt) {
void
decodeEthernetHeader(InputBuffer& buf, Pkt4Ptr& pkt) {
// The size of the buffer to be parsed must not be lower
// then the size of the Ethernet frame header.
if (buf.getLength() - buf.getPosition() < ETHERNET_HEADER_LEN) {
......@@ -53,6 +56,49 @@ void decodeEthernetHeader(InputBuffer& buf, Pkt4Ptr& pkt) {
buf.setPosition(ETHERNET_HEADER_LEN);
}
void
decodeIpUdpHeader(InputBuffer& buf, Pkt4Ptr& pkt) {
// The size of the buffer must be at least equal to the minimal size of
// the IPv4 packet header plus UDP header length.
if (buf.getLength() - buf.getPosition() < MIN_IP_HEADER_LEN + UDP_HEADER_LEN) {
isc_throw(InvalidPacketHeader, "the total size of the IP and UDP headers in "
<< "received packet is invalid, expected at least "
<< MIN_IP_HEADER_LEN + UDP_HEADER_LEN
<< " bytes, received " << buf.getLength() - buf.getPosition()
<< " bytes");
}
// Packet object must not be NULL.
if (!pkt) {
isc_throw(BadValue, "NULL packet object provided when parsing IP and UDP"
" packet headers");
}
BOOST_STATIC_ASSERT(IP_SRC_ADDR_OFFSET < MIN_IP_HEADER_LEN);
// Read IP header length (mask most significant bits as they indicate IP version).
uint8_t ip_len = buf.readUint8() & 0xF;
// IP length is the number of 4 byte chunks that construct IPv4 header.
// It must not be lower than 5 because first 20 bytes are fixed.
if (ip_len < 5) {
ip_len = 5;
}
// Seek to the position of source IP address.
buf.setPosition(IP_SRC_ADDR_OFFSET);
// Read source address.
pkt->setRemoteAddr(IOAddress(buf.readUint32()));
// Read destination address.
pkt->setLocalAddr(IOAddress(buf.readUint32()));
// Read source port from UDP header.
pkt->setRemotePort(buf.readUint16());
// Read destination port from UDP header.
pkt->setLocalPort(buf.readUint16());
// Set the pointer position to the tail of UDP header.
buf.setPosition(ip_len * 4 + UDP_HEADER_LEN);
}
void
writeEthernetHeader(const uint8_t* src_hw_addr, const uint8_t* dest_hw_addr,
OutputBuffer& out_buf) {
......
......@@ -35,6 +35,12 @@ public:
/// Size of the Ethernet frame header.
static const size_t ETHERNET_HEADER_LEN = 14;
/// Minimal IPv4 header length.
static const size_t MIN_IP_HEADER_LEN = 20;
/// UDP header length.
static const size_t UDP_HEADER_LEN = 8;
/// Offset of source address in the IPv4 header.
static const size_t IP_SRC_ADDR_OFFSET = 12;
/// @brief Decode the Ethernet header.
///
......@@ -51,6 +57,21 @@ static const size_t ETHERNET_HEADER_LEN = 14;
/// @throw BadValue if pkt object is NULL.
void decodeEthernetHeader(util::InputBuffer& buf, Pkt4Ptr& pkt);
/// @brief Decode IP and UDP header.
///
/// This function reads IP and UDP headers from the provided buffer
/// at the current read position. The source and destination IP
/// addresses and ports and read from these headers and stored in
/// the appropriate members of pkt object.
///
/// @param buf input buffer holding headers to be parsed.
/// @param [out] pkt packet object where IP addresses and ports
/// are stored.
///
/// @throw InvalidPacketHeader if packet header is truncated
/// @throw BadValue if pkt object is NULL.
void decodeIpUdpHeader(util::InputBuffer& buf, Pkt4Ptr& pkt);
/// @brief Writes ethernet frame header into a buffer.
///
/// @param src_hw_addr source HW address.
......
......@@ -124,6 +124,70 @@ TEST(ProtocolUtilTest, decodeEthernetHeader) {
EXPECT_EQ(0x01020304, dummy_data);
}
/// The purpose of this test is to verify that the IP and UDP header
/// is decoded correctly and appropriate values of IP addresses and
/// ports are assigned to a Pkt4 object.
TEST(ProtocolUtilTest, decodeIpUdpHeader) {
// IPv4 header to be parsed.
const uint8_t hdr[] = {
0x45, // IP version and header length
0x00, // TOS
0x00, 0x3c, // Total length of the IP packet.
0x1c, 0x46, // Identification field.
0x40, 0x00, // Fragmentation.
0x40, // TTL
IPPROTO_UDP, // Protocol
0x00, 0x00, // Checksum (reset to 0x00).
0xc0, 0x00, 0x02, 0x63, // Source IP address.
0xc0, 0x00, 0x02, 0x0c, // Destination IP address.
0x27, 0x54, // Source port
0x27, 0x53, // Destination port
0x00, 0x08, // UDP length
0x00, 0x00 // Checksum
};
// Write header data to the buffer.
OutputBuffer buf(1);
buf.writeData(hdr, sizeof(hdr));
// Append some dummy data.
buf.writeUint32(0x01020304);
// Create an input buffer holding truncated headers.
InputBuffer in_buf_truncated(buf.getData(), buf.getLength() - 10);
// Create non NULL Pkt4 object to make sure that the function under
// test does not throw due to invalid Pkt4 object.
Pkt4Ptr pkt(new Pkt4(DHCPDISCOVER, 0));
// Function should throw because buffer holds truncated data.
EXPECT_THROW(decodeIpUdpHeader(in_buf_truncated, pkt), InvalidPacketHeader);
// Create a valid input buffer (not truncated).
InputBuffer in_buf(buf.getData(), buf.getLength());
// Set NULL Pkt4 object to verify that function under test will
// return exception as expected.
pkt.reset();
// And check whether it throws exception.
EXPECT_THROW(decodeIpUdpHeader(in_buf, pkt), BadValue);
// Now, let's provide valid arguments and make sure it doesn't throw.
pkt.reset(new Pkt4(DHCPDISCOVER, 0));
ASSERT_TRUE(pkt);
EXPECT_NO_THROW(decodeIpUdpHeader(in_buf, pkt));
// Verify the source address and port.
EXPECT_EQ("192.0.2.99", pkt->getRemoteAddr().toText());
EXPECT_EQ(10068, pkt->getRemotePort());
// Verify the destination address and port.
EXPECT_EQ("192.0.2.12", pkt->getLocalAddr().toText());
EXPECT_EQ(10067, pkt->getLocalPort());
// Verify that the dummy data has not been corrupted and that the
// internal read pointer has been moved to the tail of the UDP
// header.
ASSERT_EQ(MIN_IP_HEADER_LEN + UDP_HEADER_LEN, in_buf.getPosition());
EXPECT_EQ(0x01020304, in_buf.readUint32());
}
/// The purpose of this test is to verify that the ethernet
/// header is correctly constructed from the destination and
/// hardware addresses.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment