<< ", must be at least 5.");
}
- // As an alternative to binary format,
+ // As an alternative to the binary format,
// we provide convenience option definition as a string in format:
// subnet1 - router1 IP addr, subnet2 - router2 IP addr, ...
// e.g.:
// 10.0.0.0/8 - 10.2.3.1, 10.229.0.128/25 - 10.1.0.3, ...
// where destination descriptors will be encoded as per RFC3442.
// We need to determine if OptionBuffer contains dash `-` separator (0x2d).
- // If not, we assume this is binary format and no encoding needs to be done.
+ // If not, we assume this is binary format.
auto begin_copy = begin;
while (begin_copy != end) {
if (*begin_copy == '-') {
if (begin_copy == end) {
// no separator found, assuming this is a hex on-wire data
- while (begin != end) {
- // check for truncated data for each static route
- if (distance(begin, end) < 5) {
- isc_throw(OutOfRange, "DHCPv4 OptionClasslessStaticRoute "
- << type_ << " has invalid length=" << distance(begin, end)
- << ", must be at least 5.");
- }
-
- // 1st octet is a width of subnet mask
- uint8_t mask_width = *begin;
- if (mask_width > 32) {
- isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
- << type_ << " has invalid value, provided width of subnet mask "
- << static_cast<int>(mask_width) << " is not valid.");
- }
-
- uint8_t significant_octets = calcSignificantOctets(mask_width);
- ++begin;
-
- // once we know haw many significant octets there are, check for truncated data again
- if (distance(begin, end) < (significant_octets + V4ADDRESS_LEN)) {
- isc_throw(OutOfRange, "DHCPv4 OptionClasslessStaticRoute "
- << type_ << " is truncated.");
- }
-
- // following octets are significant octets of the subnet nr
- uint32_t subnet_octets;
- IOAddress subnet_nr = asiolink::IOAddress::IPV4_ZERO_ADDRESS();
-
- switch (significant_octets) {
- case 0:
- // no-op - this is 0.0.0.0/0 subnet
- break;
- case 1:
- subnet_octets = *begin;
- subnet_nr = IOAddress(subnet_octets << 24);
- break ;
- case 2:
- subnet_octets = readUint16(&(*begin), distance(begin, end));
- subnet_nr = IOAddress(subnet_octets << 16);
- break ;
- case 3:
- // we are reading one octet too much in this case,
- // but since we did check for truncated data before,
- // we are safe do so and mask 4th octet with zeros
- subnet_octets = readUint32(&(*begin), distance(begin, end));
- subnet_nr = IOAddress(subnet_octets & 0xFFFFFF00);
- break ;
- case 4:
- subnet_octets = readUint32(&(*begin), distance(begin, end));
- subnet_nr = IOAddress(subnet_octets);
- break;
- }
-
- begin += significant_octets;
-
- // last comes router IPv4 address
- IOAddress router_addr = IOAddress(readUint32(&(*begin), distance(begin, end)));
- begin += V4ADDRESS_LEN;
-
- StaticRouteTuple route = std::make_tuple(subnet_nr, mask_width, router_addr);
- static_routes_.push_back(route);
- }
+ parseWireData(begin, end);
} else {
// separator was found, assuming this is option data string from config
- std::string buffer_to_str = std::string(begin, end);
- // this option allows more than one static route, so let's separate them using comma
- std::vector<std::string> tokens = str::tokens(buffer_to_str, std::string(","));
- for (const auto& route_str : tokens) {
- std::vector<std::string> parts = str::tokens(str::trim(route_str), std::string("-"));
- if (parts.size() != 2) {
- isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
- << type_ << " has invalid value, route definition must"
- " have format as in example: 10.229.0.128/25"
- " - 10.229.0.1");
- }
-
- std::string txt_prefix = str::trim(parts[0]);
-
- // Is this prefix/len notation?
- size_t pos = txt_prefix.find('/');
- if (pos == std::string::npos) {
- isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
- << type_ << " has invalid value, provided IPv4 prefix "
- << parts[0] << " is not valid.");
- }
-
- std::string txt_subnet_nr = txt_prefix.substr(0, pos);
- IOAddress subnet_nr = IOAddress("::");
- try {
- subnet_nr = IOAddress(txt_subnet_nr);
- if (!subnet_nr.isV4()) {
- isc_throw(IOError, "");
- }
- } catch (const IOError& e) {
- isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
- << type_ << " has invalid value, provided subnet_nr "
- << txt_subnet_nr << " is not a valid IPv4 address.");
- }
-
- std::string txt_prefix_len = txt_prefix.substr(pos + 1);
- int8_t len = 0;
- try {
- // We should be able to lexically cast IPv4 prefix len to short int,
- // and then downcast it to signed char. After that len<=32 check is
- // also required.
- len = boost::numeric_cast<int8_t>(boost::lexical_cast<int16_t>(txt_prefix_len));
- if (len > 32) {
- isc_throw(BadValue, "");
- }
- } catch (...) {
- isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
- << type_ << " has invalid value, provided prefix len "
- << txt_prefix_len << " is not valid.");
- }
-
- IOAddress router_addr = IOAddress("::");
- try {
- router_addr = IOAddress(str::trim(parts[1]));
- if (!router_addr.isV4()) {
- isc_throw(IOError, "");
- }
- } catch (const IOError& e) {
- isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
- << type_ << " has invalid value, provided router address "
- << parts[1] << " is not a valid IPv4 address.");
- }
-
- StaticRouteTuple route = std::make_tuple(subnet_nr, len, router_addr);
- static_routes_.push_back(route);
- }
+ std::string config_txt = std::string(begin, end);
+ parseConfigData(config_txt);
}
calcDataLen();
data_len_ = len;
}
+void
+OptionClasslessStaticRoute::parseWireData(OptionBufferConstIter begin, OptionBufferConstIter end) {
+ while (begin != end) {
+ // check for truncated data for each static route
+ if (distance(begin, end) < 5) {
+ isc_throw(OutOfRange, "DHCPv4 OptionClasslessStaticRoute "
+ << type_ << " has invalid length=" << distance(begin, end)
+ << ", must be at least 5.");
+ }
+
+ // 1st octet is a width of subnet mask
+ uint8_t mask_width = *begin;
+ if (mask_width > 32) {
+ isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
+ << type_ << " has invalid value, provided width of subnet mask "
+ << static_cast<int>(mask_width) << " is not valid.");
+ }
+
+ uint8_t significant_octets = calcSignificantOctets(mask_width);
+ ++begin;
+
+ // once we know haw many significant octets there are, check for truncated data again
+ if (distance(begin, end) < (significant_octets + V4ADDRESS_LEN)) {
+ isc_throw(OutOfRange, "DHCPv4 OptionClasslessStaticRoute "
+ << type_ << " is truncated.");
+ }
+
+ // following octets are significant octets of the subnet nr
+ uint32_t subnet_octets;
+ IOAddress subnet_nr = asiolink::IOAddress::IPV4_ZERO_ADDRESS();
+
+ switch (significant_octets) {
+ case 0:
+ // no-op - this is 0.0.0.0/0 subnet
+ break;
+ case 1:
+ subnet_octets = *begin;
+ subnet_nr = IOAddress(subnet_octets << 24);
+ break ;
+ case 2:
+ subnet_octets = readUint16(&(*begin), distance(begin, end));
+ subnet_nr = IOAddress(subnet_octets << 16);
+ break ;
+ case 3:
+ // we are reading one octet too much in this case,
+ // but since we did check for truncated data before,
+ // we are safe do so and mask 4th octet with zeros
+ subnet_octets = readUint32(&(*begin), distance(begin, end));
+ subnet_nr = IOAddress(subnet_octets & 0xFFFFFF00);
+ break ;
+ case 4:
+ subnet_octets = readUint32(&(*begin), distance(begin, end));
+ subnet_nr = IOAddress(subnet_octets);
+ break;
+ }
+
+ begin += significant_octets;
+
+ // last comes router IPv4 address
+ IOAddress router_addr = IOAddress(readUint32(&(*begin), distance(begin, end)));
+ begin += V4ADDRESS_LEN;
+
+ StaticRouteTuple route = std::make_tuple(subnet_nr, mask_width, router_addr);
+ static_routes_.push_back(route);
+ }
+}
+
+void
+OptionClasslessStaticRoute::parseConfigData(const std::string& config_txt) {
+ // this option allows more than one static route, so let's separate them using comma
+ std::vector<std::string> tokens = str::tokens(config_txt, std::string(","));
+ for (const auto& route_str : tokens) {
+ std::vector<std::string> parts = str::tokens(str::trim(route_str), std::string("-"));
+ if (parts.size() != 2) {
+ isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
+ << type_ << " has invalid value, route definition must"
+ " have format as in example: 10.229.0.128/25"
+ " - 10.229.0.1");
+ }
+
+ std::string txt_prefix = str::trim(parts[0]);
+
+ // Is this prefix/len notation?
+ size_t pos = txt_prefix.find('/');
+ if (pos == std::string::npos) {
+ isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
+ << type_ << " has invalid value, provided IPv4 prefix "
+ << parts[0] << " is not valid.");
+ }
+
+ std::string txt_subnet_nr = txt_prefix.substr(0, pos);
+ IOAddress subnet_nr = IOAddress("::");
+ try {
+ subnet_nr = IOAddress(txt_subnet_nr);
+ if (!subnet_nr.isV4()) {
+ isc_throw(IOError, "");
+ }
+ } catch (const IOError& e) {
+ isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
+ << type_ << " has invalid value, provided subnet_nr "
+ << txt_subnet_nr << " is not a valid IPv4 address.");
+ }
+
+ std::string txt_prefix_len = txt_prefix.substr(pos + 1);
+ int8_t len = 0;
+ try {
+ // We should be able to lexically cast IPv4 prefix len to short int,
+ // and then downcast it to signed char. After that len<=32 check is
+ // also required.
+ len = boost::numeric_cast<int8_t>(boost::lexical_cast<int16_t>(txt_prefix_len));
+ if (len > 32) {
+ isc_throw(BadValue, "");
+ }
+ } catch (...) {
+ isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
+ << type_ << " has invalid value, provided prefix len "
+ << txt_prefix_len << " is not valid.");
+ }
+
+ IOAddress router_addr = IOAddress("::");
+ try {
+ router_addr = IOAddress(str::trim(parts[1]));
+ if (!router_addr.isV4()) {
+ isc_throw(IOError, "");
+ }
+ } catch (const IOError& e) {
+ isc_throw(BadValue, "DHCPv4 OptionClasslessStaticRoute "
+ << type_ << " has invalid value, provided router address "
+ << parts[1] << " is not a valid IPv4 address.");
+ }
+
+ StaticRouteTuple route = std::make_tuple(subnet_nr, len, router_addr);
+ static_routes_.push_back(route);
+ }
+}
+
} // namespace dhcp
} // namespace isc
///
/// Writes option in wire-format to buffer, returns pointer to first unused
/// byte after stored option (that is useful for writing options one after
- /// another).
+ /// another). It may throw an exception if the @c packHeader method throws.
///
/// @param buf pointer to a buffer
/// @param check flag which indicates if checking the option length is
/// required (used only in V4)
- ///
- /// @throw OutOfRange Thrown when @c check param set to @c true and
- /// @c Option::packHeader(buf,check) throws due to option len>255 octets.
void pack(util::OutputBuffer& buf, bool check = true) const override;
- /// @brief Parses received wire data buffer.
+ /// @brief Parses option from the received buffer.
///
/// @param begin iterator to first byte of option data
/// @param end iterator to end of option data (first byte after option end)
- /// @throw
+ ///
+ /// @throw OutOfRange Thrown in case option contents are truncated.
void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) override;
/// @brief Returns string representation of the option.
/// Calculation is done according to static routes encoding rules in RFC3442.
/// This should be called whenever @c static_routes_ is changed.
void calcDataLen();
+
+ /// @brief Parses received wire data buffer.
+ ///
+ /// It is used by @c unpack method in case received buffer with
+ /// option data is in binary on-wire format.
+ ///
+ /// @param begin iterator to first byte of option data
+ /// @param end iterator to end of option data (first byte after option end)
+ ///
+ /// @throw OutOfRange Thrown in case option contents are truncated.
+ /// @throw BadValue Thrown in case received width of subnet mask value is invalid.
+ void parseWireData(OptionBufferConstIter begin, OptionBufferConstIter end);
+
+ /// @brief Parses a convenient notation of the option data, which may be used in config.
+ ///
+ /// As an alternative to the binary format,
+ /// we provide convenience option definition as a string in format:
+ /// subnet1 - router1 IP addr, subnet2 - router2 IP addr, ..., subnetN - routerN IP addr
+ /// e.g.:
+ /// 10.0.0.0/8 - 10.2.3.1, 10.229.0.128/25 - 10.1.0.3
+ ///
+ /// This notation may be used in the server config, thanks to the possibility of specifying
+ /// data for binary option as a single-quoted text string within double quotes
+ /// (@c csv-format flag must be set to @c false).
+ ///
+ /// @param config_txt convenient notation of the option data received as string
+ ///
+ /// @throw BadValue Thrown in case parser found wrong format of received string.
+ void parseConfigData(const std::string& config_txt);
};
-/// A pointer to the @c OptionClasslessStaticRoute object.
+/// A shared pointer to the @c OptionClasslessStaticRoute object.
typedef boost::shared_ptr<OptionClasslessStaticRoute> OptionClasslessStaticRoutePtr;
} // namespace dhcp