1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +01:00

Ported PPPoE and started porting Dot11.

This commit is contained in:
Matias Fontanini
2013-12-18 13:02:41 -03:00
parent ca6b603478
commit 33091ccbae
8 changed files with 287 additions and 235 deletions

View File

@@ -74,6 +74,11 @@ public:
*/
static const address_type BROADCAST;
/**
* The endianness used by Dot11.
*/
static const endian_type endianness = LE;
/**
* \brief Enum for the different types of 802.11 frames.
*

View File

@@ -523,6 +523,11 @@ public:
static vendor_specific_type from_bytes(const uint8_t *buffer, uint32_t sz);
};
/**
* The type used to store the QOS capability tagged option data.
*/
typedef uint8_t qos_capability_type;
/**
* \brief Getter for the second address.
@@ -641,7 +646,7 @@ public:
*
* \param new_qos_capabilities uint8_t with the capabilities.
*/
void qos_capability(uint8_t new_qos_capability);
void qos_capability(qos_capability_type new_qos_capability);
/**
* \brief Helper method to set the power capabilities option.
@@ -851,7 +856,7 @@ public:
*
* \return uint8_t containing the QOS capability.
*/
uint8_t qos_capability() const;
qos_capability_type qos_capability() const;
/**
* \brief Helper method to get the power capability.
@@ -1120,6 +1125,14 @@ protected:
private:
static uint8_t *serialize_rates(const rates_type &rates);
static rates_type deserialize_rates(const option *option);
template<typename T>
T search_and_convert(OptionTypes opt_type) const {
const option *opt = search_option(opt_type);
if(!opt)
throw option_not_found();
return opt->to<T>();
}
ExtendedHeader _ext_header;
address_type _addr4;

View File

@@ -33,6 +33,7 @@
#include <vector>
#include <iterator>
#include <algorithm>
#include <string>
#include <stdint.h>
#include "exceptions.h"
#include "endianness.h"
@@ -113,6 +114,30 @@ namespace Internals {
}
};
template<>
struct converter<std::string> {
template<typename X, typename PDUType>
static std::string convert(const PDUOption<X, PDUType>& opt) {
return std::string(
opt.data_ptr(),
opt.data_ptr() + opt.data_size()
);
}
};
template<>
struct converter<std::vector<float> > {
template<typename X, typename PDUType>
static std::vector<float> convert(const PDUOption<X, PDUType>& opt) {
std::vector<float> output;
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
while(ptr != end) {
output.push_back(float(*(ptr++) & 0x7f) / 2);
}
return output;
}
};
template<typename T>
struct converter<std::vector<T>, typename enable_if<is_unsigned_integral<T>::value>::type> {
template<typename X, typename PDUType>
@@ -134,6 +159,40 @@ namespace Internals {
}
};
template<typename T, typename U>
struct converter<
std::vector<std::pair<T, U> >,
typename enable_if<
is_unsigned_integral<T>::value && is_unsigned_integral<U>::value
>::type
> {
template<typename X, typename PDUType>
static std::vector<std::pair<T, U> > convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() % (sizeof(T) + sizeof(U)) != 0)
throw malformed_option();
const uint8_t *ptr = opt.data_ptr(), *end = ptr + opt.data_size();
std::vector<std::pair<T, U> > output;
while(ptr < end) {
std::pair<T, U> data;
data.first = *(const T*)ptr;
ptr += sizeof(T);
data.second = *(const U*)ptr;
ptr += sizeof(U);
if(PDUType::endianness == PDUType::BE) {
data.first = Endian::be_to_host(data.first);
data.second = Endian::be_to_host(data.second);
}
else {
data.first = Endian::le_to_host(data.first);
data.second = Endian::le_to_host(data.second);
}
output.push_back(data);
}
return output;
}
};
template<>
struct converter<std::vector<IPv4Address> > {
template<typename X, typename PDUType>
@@ -172,7 +231,12 @@ namespace Internals {
};
template<typename T, typename U>
struct converter<std::pair<T, U>, typename enable_if<is_unsigned_integral<T>::value>::type> {
struct converter<
std::pair<T, U>,
typename enable_if<
is_unsigned_integral<T>::value && is_unsigned_integral<U>::value
>::type
> {
template<typename X, typename PDUType>
static std::pair<T, U> convert(const PDUOption<X, PDUType>& opt) {
if(opt.data_size() != sizeof(T) + sizeof(U))

View File

@@ -90,6 +90,8 @@ public:
vendor_spec_type(uint32_t vendor_id = 0, const data_type &data = data_type())
: vendor_id(vendor_id), data(data) { }
static vendor_spec_type from_option(const tag &opt);
};
/**
@@ -397,19 +399,11 @@ private:
}
template<typename T>
T retrieve_tag_iterable(TagTypes id) const {
const tag *tag = search_tag(id);
if(!tag)
T search_and_convert(TagTypes id) const {
const tag *t = search_tag(id);
if(!t)
throw option_not_found();
return T(tag->data_ptr(), tag->data_ptr() + tag->data_size());
}
template<template <typename> class Functor>
const tag *safe_search_tag(TagTypes opt, uint32_t size) const {
const tag *option = search_tag(opt);
if(!option || Functor<uint32_t>()(option->data_size(), size))
throw option_not_found();
return option;
return t->to<T>();
}
TINS_BEGIN_PACK

View File

@@ -35,152 +35,160 @@
#include "endianness.h"
namespace Tins{
class Dot11;
template<typename T, typename U>
class PDUOption;
/**
* \brief Class that models the RSN information structure.
*/
class RSNInformation {
public:
/**
* \brief Class that models the RSN information structure.
* \brief Enum that represents the different cypher suites.
*/
class RSNInformation {
public:
/**
* \brief Enum that represents the different cypher suites.
*/
enum CypherSuites {
WEP_40 = 0x01ac0f00,
TKIP = 0x02ac0f00,
CCMP = 0x04ac0f00,
WEP_104 = 0x05ac0f00
};
/**
* \brief Enum that represents the different akm suites.
*/
enum AKMSuites {
PMKSA = 0x01ac0f00,
PSK = 0x02ac0f00
};
/**
* The type used to store the cypher suites.
*/
typedef std::vector<CypherSuites> cyphers_type;
/**
* The type used to store the AKM suites.
*/
typedef std::vector<AKMSuites> akm_type;
/**
* The type returned on serialization.
*/
typedef std::vector<uint8_t> serialization_type;
/**
* \brief Constructs an RSNInformation object.
*
* By default, the version is set to 1.
*/
RSNInformation();
/**
* \brief Constructs an RSNInformation object from a
* serialization_type object.
*
* \param buffer The buffer from which to construct this object.
*/
RSNInformation(const serialization_type &buffer);
/**
* \brief Constructs a RSNInformation from a buffer.
*
* If the input is malformed, a malformed_packet exception is
* thrown.
*
* \param buffer The buffer from which this object will be constructed.
* \param total_sz The total size of the buffer.
*/
RSNInformation(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Helper function to create a WPA2-PSK RSNInformation
* \return An instance RSNInformation which contains information
* for a WPA2-PSK AP.
*/
static RSNInformation wpa2_psk();
/**
* \brief Adds a pairwise cypher suite.
* \param cypher The pairwise cypher suite to be added.
*/
void add_pairwise_cypher(CypherSuites cypher);
/**
* \brief Adds an akm suite.
* \param akm The akm suite to be added.
*/
void add_akm_cypher(AKMSuites akm);
/**
* \brief Sets the group suite cypher.
* \param group The group suite cypher to be set.
*/
void group_suite(CypherSuites group);
/**
* \brief Sets the version.
* \param ver The version to be set.
*/
void version(uint16_t ver);
/**
* \brief Sets the capabilities field.
* \param cap The capabilities to be set.
*/
void capabilities(uint16_t cap);
/* Getters */
/**
* \brief Getter for the group suite field.
* \return The group suite field.
*/
CypherSuites group_suite() const { return _group_suite; }
/**
* \brief Getter for the version field.
* \return The version field.
*/
uint16_t version() const { return Endian::le_to_host(_version); }
/**
* \brief Getter for the capabilities field.
* \return The version field.
*/
uint16_t capabilities() const { return Endian::le_to_host(_capabilities); }
/**
* \brief Getter for the pairwise cypher suite list.
* \return A list of pairwise cypher suites.
*/
const cyphers_type &pairwise_cyphers() const { return _pairwise_cyphers; }
/**
* \brief Getter for the akm suite list.
* \return A list of akm suites.
*/
const akm_type &akm_cyphers() const { return _akm_cyphers; }
/**
* \brief Serializes this object.
* \return The result of the serialization.
*/
serialization_type serialize() const;
private:
void init(const uint8_t *buffer, uint32_t total_sz);
uint16_t _version, _capabilities;
CypherSuites _group_suite;
akm_type _akm_cyphers;
cyphers_type _pairwise_cyphers;
enum CypherSuites {
WEP_40 = 0x01ac0f00,
TKIP = 0x02ac0f00,
CCMP = 0x04ac0f00,
WEP_104 = 0x05ac0f00
};
/**
* \brief Enum that represents the different akm suites.
*/
enum AKMSuites {
PMKSA = 0x01ac0f00,
PSK = 0x02ac0f00
};
/**
* The type used to store the cypher suites.
*/
typedef std::vector<CypherSuites> cyphers_type;
/**
* The type used to store the AKM suites.
*/
typedef std::vector<AKMSuites> akm_type;
/**
* The type returned on serialization.
*/
typedef std::vector<uint8_t> serialization_type;
/**
* \brief Constructs an RSNInformation object.
*
* By default, the version is set to 1.
*/
RSNInformation();
/**
* \brief Constructs an RSNInformation object from a
* serialization_type object.
*
* \param buffer The buffer from which to construct this object.
*/
RSNInformation(const serialization_type &buffer);
/**
* \brief Constructs a RSNInformation from a buffer.
*
* If the input is malformed, a malformed_packet exception is
* thrown.
*
* \param buffer The buffer from which this object will be constructed.
* \param total_sz The total size of the buffer.
*/
RSNInformation(const uint8_t *buffer, uint32_t total_sz);
/**
* \brief Helper function to create a WPA2-PSK RSNInformation
* \return An instance RSNInformation which contains information
* for a WPA2-PSK AP.
*/
static RSNInformation wpa2_psk();
/**
* \brief Adds a pairwise cypher suite.
* \param cypher The pairwise cypher suite to be added.
*/
void add_pairwise_cypher(CypherSuites cypher);
/**
* \brief Adds an akm suite.
* \param akm The akm suite to be added.
*/
void add_akm_cypher(AKMSuites akm);
/**
* \brief Sets the group suite cypher.
* \param group The group suite cypher to be set.
*/
void group_suite(CypherSuites group);
/**
* \brief Sets the version.
* \param ver The version to be set.
*/
void version(uint16_t ver);
/**
* \brief Sets the capabilities field.
* \param cap The capabilities to be set.
*/
void capabilities(uint16_t cap);
/* Getters */
/**
* \brief Getter for the group suite field.
* \return The group suite field.
*/
CypherSuites group_suite() const { return _group_suite; }
/**
* \brief Getter for the version field.
* \return The version field.
*/
uint16_t version() const { return Endian::le_to_host(_version); }
/**
* \brief Getter for the capabilities field.
* \return The version field.
*/
uint16_t capabilities() const { return Endian::le_to_host(_capabilities); }
/**
* \brief Getter for the pairwise cypher suite list.
* \return A list of pairwise cypher suites.
*/
const cyphers_type &pairwise_cyphers() const { return _pairwise_cyphers; }
/**
* \brief Getter for the akm suite list.
* \return A list of akm suites.
*/
const akm_type &akm_cyphers() const { return _akm_cyphers; }
/**
* \brief Serializes this object.
* \return The result of the serialization.
*/
serialization_type serialize() const;
/**
* Constructs an RSNInformation object from a Dot11 tagged option.
*/
static RSNInformation from_option(const PDUOption<uint8_t, Dot11> &opt);
private:
void init(const uint8_t *buffer, uint32_t total_sz);
uint16_t _version, _capabilities;
CypherSuites _group_suite;
akm_type _akm_cyphers;
cyphers_type _pairwise_cyphers;
};
} // namespace Tins
#endif // TINS_RSN_INFORMATION

View File

@@ -149,7 +149,7 @@ void Dot11ManagementFrame::extended_supported_rates(const rates_type &new_rates)
delete[] buffer;
}
void Dot11ManagementFrame::qos_capability(uint8_t new_qos_capability) {
void Dot11ManagementFrame::qos_capability(qos_capability_type new_qos_capability) {
add_tagged_option(QOS_CAPABILITY, 1, &new_qos_capability);
}
@@ -370,10 +370,7 @@ void Dot11ManagementFrame::vendor_specific(const vendor_specific_type &data) {
// Getters
RSNInformation Dot11ManagementFrame::rsn_information() {
const Dot11::option *option = search_option(RSN);
if(!option || option->data_size() < (sizeof(uint16_t) << 1) + sizeof(uint32_t))
throw option_not_found();
return RSNInformation(option->data_ptr(), option->data_size());
return search_and_convert<RSNInformation>(RSN);
}
std::string Dot11ManagementFrame::ssid() const {
@@ -387,55 +384,27 @@ std::string Dot11ManagementFrame::ssid() const {
}
Dot11ManagementFrame::rates_type Dot11ManagementFrame::supported_rates() const {
const Dot11::option *option = search_option(SUPPORTED_RATES);
if(!option || option->data_size() == 0)
throw option_not_found();
return deserialize_rates(option);
return search_and_convert<rates_type>(SUPPORTED_RATES);
}
Dot11ManagementFrame::rates_type Dot11ManagementFrame::extended_supported_rates() const {
const Dot11::option *option = search_option(EXT_SUPPORTED_RATES);
if(!option || option->data_size() == 0)
throw option_not_found();
return deserialize_rates(option);
return search_and_convert<rates_type>(EXT_SUPPORTED_RATES);
}
uint8_t Dot11ManagementFrame::qos_capability() const {
const Dot11::option *option = search_option(QOS_CAPABILITY);
if(!option || option->data_size() != 1)
throw option_not_found();
return *option->data_ptr();
Dot11ManagementFrame::qos_capability_type Dot11ManagementFrame::qos_capability() const {
return search_and_convert<uint8_t>(QOS_CAPABILITY);
}
std::pair<uint8_t, uint8_t> Dot11ManagementFrame::power_capability() const {
const Dot11::option *option = search_option(POWER_CAPABILITY);
if(!option || option->data_size() != 2)
throw option_not_found();
return std::make_pair(*option->data_ptr(), *(option->data_ptr() + 1));
return search_and_convert<std::pair<uint8_t, uint8_t> >(POWER_CAPABILITY);
}
Dot11ManagementFrame::channels_type Dot11ManagementFrame::supported_channels() const {
const Dot11::option *option = search_option(SUPPORTED_CHANNELS);
// We need a multiple of two
if(!option || ((option->data_size() & 0x1) == 1))
throw option_not_found();
channels_type output;
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
while(ptr != end) {
uint8_t first = *(ptr++);
output.push_back(std::make_pair(first, *(ptr++)));
}
return output;
return search_and_convert<channels_type>(SUPPORTED_CHANNELS);
}
Dot11ManagementFrame::request_info_type Dot11ManagementFrame::request_information() const {
const Dot11::option *option = search_option(REQUEST_INFORMATION);
if(!option || option->data_size() == 0)
throw option_not_found();
request_info_type output;
const uint8_t *ptr = option->data_ptr(), *end = ptr + option->data_size();
output.assign(ptr, end);
return output;
return search_and_convert<request_info_type>(REQUEST_INFORMATION);
}
Dot11ManagementFrame::fh_params_set Dot11ManagementFrame::fh_parameter_set() const {
@@ -451,10 +420,7 @@ Dot11ManagementFrame::fh_params_set Dot11ManagementFrame::fh_parameter_set() con
}
uint8_t Dot11ManagementFrame::ds_parameter_set() const {
const Dot11::option *option = search_option(DS_SET);
if(!option || option->data_size() != sizeof(uint8_t))
throw option_not_found();
return *option->data_ptr();
return search_and_convert<uint8_t>(DS_SET);
}
Dot11ManagementFrame::cf_params_set Dot11ManagementFrame::cf_parameter_set() const {
@@ -470,10 +436,7 @@ Dot11ManagementFrame::cf_params_set Dot11ManagementFrame::cf_parameter_set() con
}
uint16_t Dot11ManagementFrame::ibss_parameter_set() const {
const Dot11::option *option = search_option(IBSS_SET);
if(!option || option->data_size() != sizeof(uint16_t))
throw option_not_found();
return Endian::le_to_host(*reinterpret_cast<const uint16_t*>(option->data_ptr()));
return search_and_convert<uint16_t>(IBSS_SET);
}
Dot11ManagementFrame::ibss_dfs_params Dot11ManagementFrame::ibss_dfs() const {
@@ -513,12 +476,7 @@ Dot11ManagementFrame::country_params Dot11ManagementFrame::country() const {
}
std::pair<uint8_t, uint8_t> Dot11ManagementFrame::fh_parameters() const {
const Dot11::option *option = search_option(HOPPING_PATTERN_PARAMS);
if(!option || option->data_size() != sizeof(uint8_t) * 2)
throw option_not_found();
const uint8_t *ptr = option->data_ptr();
uint8_t first = *(ptr++);
return std::make_pair(first, *ptr);
return search_and_convert<std::pair<uint8_t, uint8_t> >(HOPPING_PATTERN_PARAMS);
}
Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_table() const {
@@ -538,10 +496,7 @@ Dot11ManagementFrame::fh_pattern_type Dot11ManagementFrame::fh_pattern_table() c
}
uint8_t Dot11ManagementFrame::power_constraint() const {
const Dot11::option *option = search_option(POWER_CONSTRAINT);
if(!option || option->data_size() != 1)
throw option_not_found();
return *option->data_ptr();
return search_and_convert<uint8_t>(POWER_CONSTRAINT);
}
Dot11ManagementFrame::channel_switch_type Dot11ManagementFrame::channel_switch() const {
@@ -642,4 +597,4 @@ Dot11ManagementFrame::vendor_specific_type
} // namespace Tins
#endif // HAVE_DOT11
#endif // HAVE_DOT11

View File

@@ -192,48 +192,54 @@ void PPPoE::generic_error(const std::string &value) {
// *********************** Getters *************************
std::string PPPoE::service_name() const {
return retrieve_tag_iterable<std::string>(SERVICE_NAME);
return search_and_convert<std::string>(SERVICE_NAME);
}
std::string PPPoE::ac_name() const {
return retrieve_tag_iterable<std::string>(AC_NAME);
return search_and_convert<std::string>(AC_NAME);
}
byte_array PPPoE::host_uniq() const {
return retrieve_tag_iterable<byte_array>(HOST_UNIQ);
return search_and_convert<byte_array>(HOST_UNIQ);
}
byte_array PPPoE::ac_cookie() const {
return retrieve_tag_iterable<byte_array>(AC_COOKIE);
return search_and_convert<byte_array>(AC_COOKIE);
}
PPPoE::vendor_spec_type PPPoE::vendor_specific() const {
const tag *tag = safe_search_tag<std::less>(
VENDOR_SPECIFIC, sizeof(uint32_t)
);
vendor_spec_type output;
output.vendor_id = Endian::be_to_host(*(const uint32_t*)tag->data_ptr());
output.data.assign(
tag->data_ptr() + sizeof(uint32_t),
tag->data_ptr() + tag->data_size()
);
return output;
const tag *t = search_tag(VENDOR_SPECIFIC);
if(!t)
throw option_not_found();
return t->to<vendor_spec_type>();
}
byte_array PPPoE::relay_session_id() const {
return retrieve_tag_iterable<byte_array>(RELAY_SESSION_ID);
return search_and_convert<byte_array>(RELAY_SESSION_ID);
}
std::string PPPoE::service_name_error() const {
return retrieve_tag_iterable<std::string>(SERVICE_NAME_ERROR);
return search_and_convert<std::string>(SERVICE_NAME_ERROR);
}
std::string PPPoE::ac_system_error() const {
return retrieve_tag_iterable<std::string>(AC_SYSTEM_ERROR);
return search_and_convert<std::string>(AC_SYSTEM_ERROR);
}
std::string PPPoE::generic_error() const {
return retrieve_tag_iterable<std::string>(GENERIC_ERROR);
return search_and_convert<std::string>(GENERIC_ERROR);
}
PPPoE::vendor_spec_type PPPoE::vendor_spec_type::from_option(const tag &opt) {
if(opt.data_size() < sizeof(uint32_t))
throw malformed_option();
vendor_spec_type output;
output.vendor_id = Endian::be_to_host(*(const uint32_t*)opt.data_ptr());
output.data.assign(
opt.data_ptr() + sizeof(uint32_t),
opt.data_ptr() + opt.data_size()
);
return output;
}
} //namespace Tins

View File

@@ -30,6 +30,7 @@
#include <stdexcept>
#include "rsn_information.h"
#include "exceptions.h"
#include "dot11/dot11_base.h"
namespace Tins {
template<typename T>
@@ -143,4 +144,10 @@ RSNInformation RSNInformation::wpa2_psk() {
info.add_akm_cypher(RSNInformation::PSK);
return info;
}
RSNInformation RSNInformation::from_option(const PDUOption<uint8_t, Dot11> &opt) {
if(opt.data_size() < sizeof(uint16_t) * 2 + sizeof(uint32_t))
throw malformed_option();
return RSNInformation(opt.data_ptr(), opt.data_size());
}
}