Kea 1.5.0
pkt_transform.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <iostream>
10
12#include <dhcp/option.h>
13#include <dhcp/libdhcp++.h>
14#include <dhcp/dhcp6.h>
15
16#include "pkt_transform.h"
17#include "localized_option.h"
18
19using namespace std;
20using namespace isc;
21using namespace dhcp;
22
23namespace isc {
24namespace perfdhcp {
25
26bool
28 const OptionBuffer& in_buffer,
29 const OptionCollection& options,
30 const size_t transid_offset,
31 const uint32_t transid,
32 util::OutputBuffer& out_buffer) {
33
34 // Always override the packet if function is called.
35 out_buffer.clear();
36 // Write whole buffer to output buffer.
37 out_buffer.writeData(&in_buffer[0], in_buffer.size());
38
39 uint8_t transid_len = (universe == Option::V6) ? 3 : 4;
40
41 if ((transid_offset + transid_len >= in_buffer.size()) ||
42 (transid_offset == 0)) {
43 cout << "Failed to build packet: provided transaction id offset: "
44 << transid_offset << " is out of bounds (expected 1.."
45 << in_buffer.size()-1 << ")." << endl;
46 return (false);
47 }
48
49 try {
50 size_t offset_ptr = transid_offset;
51 if (universe == Option::V4) {
52 out_buffer.writeUint8At(transid >> 24 & 0xFF, offset_ptr++);
53 }
54 out_buffer.writeUint8At(transid >> 16 & 0xFF, offset_ptr++);
55 out_buffer.writeUint8At(transid >> 8 & 0xFF, offset_ptr++);
56 out_buffer.writeUint8At(transid & 0xFF, offset_ptr++);
57
58 // We already have packet template stored in output buffer
59 // but still some options have to be updated if client
60 // specified them along with their offsets in the buffer.
61 PktTransform::packOptions(in_buffer, options, out_buffer);
62 } catch (const isc::BadValue& e) {
63 cout << "Building packet failed: " << e.what() << endl;
64 return (false);
65 }
66 return (true);
67}
68
69bool
71 const OptionBuffer& in_buffer,
72 const OptionCollection& options,
73 const size_t transid_offset,
74 uint32_t& transid) {
75
76 uint8_t transid_len = (universe == Option::V6) ? 3 : 4;
77
78 // Validate transaction id offset.
79 if ((transid_offset + transid_len + 1 > in_buffer.size()) ||
80 (transid_offset == 0)) {
81 cout << "Failed to parse packet: provided transaction id offset: "
82 << transid_offset << " is out of bounds (expected 1.."
83 << in_buffer.size()-1 << ")." << endl;
84 return (false);
85 }
86
87 // Read transaction id from the buffer.
88 // For DHCPv6 we transaction id is 3 bytes long so the high byte
89 // of transid will be zero.
90 OptionBufferConstIter it = in_buffer.begin() + transid_offset;
91 transid = 0;
92 for (int i = 0; i < transid_len; ++i, ++it) {
93 // Read next byte and shift it left to its position in
94 // transid (shift by the number of bytes read so far.
95 transid += *it << (transid_len - i - 1) * 8;
96 }
97
98 try {
99 PktTransform::unpackOptions(in_buffer, options);
100 } catch (const isc::BadValue& e) {
101 cout << "Packet parsing failed: " << e.what() << endl;
102 return (false);
103 }
104
105 return (true);
106}
107
108void
109PktTransform::packOptions(const OptionBuffer& in_buffer,
110 const OptionCollection& options,
111 util::OutputBuffer& out_buffer) {
112 try {
113 // If there are any options on the list, we will use provided
114 // options offsets to override them in the output buffer
115 // with new contents.
116 for (OptionCollection::const_iterator it = options.begin();
117 it != options.end(); ++it) {
118 // Get options with their position (offset).
119 boost::shared_ptr<LocalizedOption> option =
120 boost::dynamic_pointer_cast<LocalizedOption>(it->second);
121 if (option == NULL) {
122 isc_throw(isc::BadValue, "option is null");
123 }
124 uint32_t offset = option->getOffset();
125 if ((offset == 0) ||
126 (offset + option->len() > in_buffer.size())) {
128 "option offset for option: " << option->getType()
129 << " is out of bounds (expected 1.."
130 << in_buffer.size() - option->len() << ")");
131 }
132
133 // Create temporary buffer to store option contents.
134 util::OutputBuffer buf(option->len());
135 // Pack option contents into temporary buffer.
136 option->pack(buf);
137 // OutputBuffer class has nice functions that write
138 // data at the specified position so we can use it to
139 // inject contents of temporary buffer to output buffer.
140 const uint8_t *buf_data =
141 static_cast<const uint8_t*>(buf.getData());
142 for (size_t i = 0; i < buf.getLength(); ++i) {
143 out_buffer.writeUint8At(buf_data[i], offset + i);
144 }
145 }
146 }
147 catch (const Exception&) {
148 isc_throw(isc::BadValue, "failed to pack options into buffer.");
149 }
150}
151
152void
153PktTransform::unpackOptions(const OptionBuffer& in_buffer,
154 const OptionCollection& options) {
155 for (OptionCollection::const_iterator it = options.begin();
156 it != options.end(); ++it) {
157
158 boost::shared_ptr<LocalizedOption> option =
159 boost::dynamic_pointer_cast<LocalizedOption>(it->second);
160 if (option == NULL) {
161 isc_throw(isc::BadValue, "option is null");
162 }
163 size_t opt_pos = option->getOffset();
164 if (opt_pos == 0) {
165 isc_throw(isc::BadValue, "failed to unpack packet from raw buffer "
166 "(Option position not specified)");
167 } else if (opt_pos + option->getHeaderLen() > in_buffer.size()) {
169 "failed to unpack options from from raw buffer "
170 "(Option position out of bounds)");
171 }
172
173 size_t offset = opt_pos;
174 size_t offset_step = 1;
175 uint16_t opt_type = 0;
176 if (option->getUniverse() == Option::V6) {
177 offset_step = 2;
178 // For DHCPv6 option type is in first two octets.
179 opt_type = in_buffer[offset] * 256 + in_buffer[offset + 1];
180 } else {
181 // For DHCPv4 option type is in first octet.
182 opt_type = in_buffer[offset];
183 }
184 // Check if we got expected option type.
185 if (opt_type != option->getType()) {
187 "failed to unpack option from raw buffer "
188 "(option type mismatch)");
189 }
190
191 // Get option length which is supposed to be after option type.
192 offset += offset_step;
193 const uint16_t opt_len =
194 (option->getUniverse() == Option::V6) ?
195 in_buffer[offset] * 256 + in_buffer[offset + 1] :
196 in_buffer[offset];
197
198 // Check if packet is not truncated.
199 if (offset + option->getHeaderLen() + opt_len > in_buffer.size()) {
201 "failed to unpack option from raw buffer "
202 "(option truncated)");
203 }
204
205 // Seek to actual option data and replace it.
206 offset += offset_step;
207 option->setData(in_buffer.begin() + offset,
208 in_buffer.begin() + offset + opt_len);
209 }
210}
211
212void
213PktTransform::writeAt(dhcp::OptionBuffer& in_buffer, size_t dest_pos,
214 dhcp::OptionBuffer::iterator first,
215 dhcp::OptionBuffer::iterator last) {
216 memcpy(&in_buffer[dest_pos], &(*first), std::distance(first, last));
217}
218
219} // namespace perfdhcp
220} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:67
static bool unpack(const dhcp::Option::Universe universe, const dhcp::OptionBuffer &in_buffer, const dhcp::OptionCollection &options, const size_t transid_offset, uint32_t &transid)
Handles selective binary packet parsing.
static void writeAt(dhcp::OptionBuffer &in_buffer, size_t dest_pos, std::vector< uint8_t >::iterator first, std::vector< uint8_t >::iterator last)
Replace contents of buffer with vector.
static bool pack(const dhcp::Option::Universe universe, const dhcp::OptionBuffer &in_buffer, const dhcp::OptionCollection &options, const size_t transid_offset, const uint32_t transid, util::OutputBuffer &out_buffer)
Prepares on-wire format from raw buffer.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
void writeUint8At(uint8_t data, size_t pos)
Write an unsigned 8-bit integer into the buffer.
Definition: buffer.h:476
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:547
void clear()
Clear buffer content.
Definition: buffer.h:448
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
OptionBuffer::const_iterator OptionBufferConstIter
const_iterator for walking over OptionBuffer
Definition: option.h:31
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
Definition: option.h:41
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:25
Defines the logger used by the top-level component of kea-dhcp-ddns.