// 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) {
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) {
/// 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.
///
/// @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.
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.