traffic-selector-substructure: Add support for TS_SECLABEL

Changes how regular address range traffic selectors are parsed as the
IKE parser currently doesn't provide sub-type parsing.

Also removed a lot of unused method definitions.
This commit is contained in:
Tobias Brunner
2022-04-14 18:42:01 +02:00
parent d71d181d28
commit a44de0b957
2 changed files with 189 additions and 137 deletions
@@ -14,11 +14,33 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/*
* Copyright (C) 2022 Tobias Brunner, codelabs GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "traffic_selector_substructure.h"
#include <encoding/payloads/encodings.h>
#include <collections/linked_list.h>
#include <bio/bio_reader.h>
#include <bio/bio_writer.h>
typedef struct private_traffic_selector_substructure_t private_traffic_selector_substructure_t;
@@ -48,50 +70,32 @@ struct private_traffic_selector_substructure_t {
uint16_t payload_length;
/**
* Start port number.
* Port/address range or security label.
*/
uint16_t start_port;
/**
* End port number.
*/
uint16_t end_port;
/**
* Starting address.
*/
chunk_t starting_address;
/**
* Ending address.
*/
chunk_t ending_address;
chunk_t ts_data;
};
/**
* Encoding rules to parse or generate a TS payload
* Encoding rules to parse or generate a TS payload.
*
* Due to the generic nature of security labels, the actual structure of regular
* TS is not parsed with these rules.
*
* The defined offsets are the positions in a object of type
* private_traffic_selector_substructure_t.
*/
static encoding_rule_t encodings[] = {
/* 1 Byte next ts type*/
{ TS_TYPE, offsetof(private_traffic_selector_substructure_t, ts_type) },
{ U_INT_8, offsetof(private_traffic_selector_substructure_t, ts_type) },
/* 1 Byte IP protocol id*/
{ U_INT_8, offsetof(private_traffic_selector_substructure_t, ip_protocol_id) },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH,offsetof(private_traffic_selector_substructure_t, payload_length) },
/* 2 Byte start port*/
{ U_INT_16, offsetof(private_traffic_selector_substructure_t, start_port) },
/* 2 Byte end port*/
{ U_INT_16, offsetof(private_traffic_selector_substructure_t, end_port) },
/* starting address is either 4 or 16 byte */
{ ADDRESS, offsetof(private_traffic_selector_substructure_t, starting_address) },
/* ending address is either 4 or 16 byte */
{ ADDRESS, offsetof(private_traffic_selector_substructure_t, ending_address) }
/* traffic selector data, length is defined in PAYLOAD_LENGTH */
{ CHUNK_DATA, offsetof(private_traffic_selector_substructure_t, ts_data) },
};
/*
/* Regular traffic selectors for address ranges:
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -107,48 +111,91 @@ static encoding_rule_t encodings[] = {
~ Ending Address* ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* Security labels:
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------------------------------+
| TS Type | Reserved | Selector Length |
+---------------+---------------+-------------------------------+
| |
~ Security Label* ~
| |
+---------------------------------------------------------------+
*/
/**
* Parse the data of a regular address range traffic selector.
*/
static bool parse_ts_data(private_traffic_selector_substructure_t *this,
uint16_t *start_port, uint16_t *end_port,
chunk_t *start_addr, chunk_t *end_addr)
{
bio_reader_t *reader;
int addr_len;
switch (this->ts_type)
{
case TS_IPV4_ADDR_RANGE:
addr_len = 4;
break;
case TS_IPV6_ADDR_RANGE:
addr_len = 16;
break;
default:
return FALSE;
}
reader = bio_reader_create(this->ts_data);
if (!reader->read_uint16(reader, start_port) ||
!reader->read_uint16(reader, end_port) ||
!reader->read_data(reader, addr_len, start_addr) ||
!reader->read_data(reader, addr_len, end_addr) ||
reader->remaining(reader) > 0)
{
reader->destroy(reader);
return FALSE;
}
reader->destroy(reader);
return TRUE;
}
METHOD(payload_t, verify, status_t,
private_traffic_selector_substructure_t *this)
{
if (this->start_port > this->end_port)
{
/* OPAQUE ports are the only exception */
if (this->start_port != 0xffff && this->end_port != 0)
{
return FAILED;
}
}
switch (this->ts_type)
{
case TS_IPV4_ADDR_RANGE:
{
if ((this->starting_address.len != 4) ||
(this->ending_address.len != 4))
{
/* ipv4 address must be 4 bytes long */
return FAILED;
}
break;
}
case TS_IPV6_ADDR_RANGE:
{
if ((this->starting_address.len != 16) ||
(this->ending_address.len != 16))
uint16_t start_port, end_port;
chunk_t start_addr, end_addr;
if (!parse_ts_data(this, &start_port, &end_port, &start_addr,
&end_addr))
{
/* ipv6 address must be 16 bytes long */
return FAILED;
}
if (start_port > end_port)
{
/* OPAQUE ports are the only exception */
if (start_port != 0xffff && end_port != 0)
{
return FAILED;
}
}
break;
}
case TS_SECLABEL:
if (!this->ts_data.len)
{
return FAILED;
}
break;
default:
{
/* not supported ts type */
return FAILED;
}
/* unsupported TS type, just ignored later */
break;
}
return SUCCESS;
}
@@ -162,7 +209,7 @@ METHOD(payload_t, get_encoding_rules, int,
METHOD(payload_t, get_header_length, int,
private_traffic_selector_substructure_t *this)
{
return 8;
return 4;
}
METHOD(payload_t, get_type, payload_type_t,
@@ -191,17 +238,32 @@ METHOD(payload_t, get_length, size_t,
METHOD(traffic_selector_substructure_t, get_traffic_selector, traffic_selector_t*,
private_traffic_selector_substructure_t *this)
{
uint16_t start_port, end_port;
chunk_t start_addr, end_addr;
if (!parse_ts_data(this, &start_port, &end_port, &start_addr, &end_addr))
{
return NULL;
}
return traffic_selector_create_from_bytes(
this->ip_protocol_id, this->ts_type,
this->starting_address, this->start_port,
this->ending_address, this->end_port);
start_addr, start_port, end_addr, end_port);
}
METHOD(traffic_selector_substructure_t, get_sec_label, sec_label_t*,
private_traffic_selector_substructure_t *this)
{
if (this->ts_type != TS_SECLABEL)
{
return NULL;
}
return sec_label_from_encoding(this->ts_data);
}
METHOD2(payload_t, traffic_selector_substructure_t, destroy, void,
private_traffic_selector_substructure_t *this)
{
free(this->starting_address.ptr);
free(this->ending_address.ptr);
free(this->ts_data.ptr);
free(this);
}
@@ -225,6 +287,7 @@ traffic_selector_substructure_t *traffic_selector_substructure_create()
.destroy = _destroy,
},
.get_traffic_selector = _get_traffic_selector,
.get_sec_label = _get_sec_label,
.destroy = _destroy,
},
.payload_length = get_header_length(this),
@@ -241,16 +304,34 @@ traffic_selector_substructure_t *traffic_selector_substructure_create_from_traff
traffic_selector_t *ts)
{
private_traffic_selector_substructure_t *this;
bio_writer_t *writer;
this = (private_traffic_selector_substructure_t*)traffic_selector_substructure_create();
this->ts_type = ts->get_type(ts);
this->ip_protocol_id = ts->get_protocol(ts);
this->start_port = ts->get_from_port(ts);
this->end_port = ts->get_to_port(ts);
this->starting_address = chunk_clone(ts->get_from_address(ts));
this->ending_address = chunk_clone(ts->get_to_address(ts));
this->payload_length = get_header_length(this) +
this->ending_address.len + this->starting_address.len;
writer = bio_writer_create(this->ts_type == TS_IPV4_ADDR_RANGE ? 12 : 36);
writer->write_uint16(writer, ts->get_from_port(ts));
writer->write_uint16(writer, ts->get_to_port(ts));
writer->write_data(writer, ts->get_from_address(ts));
writer->write_data(writer, ts->get_to_address(ts));
this->ts_data = writer->extract_buf(writer);
this->payload_length += this->ts_data.len;
writer->destroy(writer);
return &this->public;
}
/*
* Described in header
*/
traffic_selector_substructure_t *traffic_selector_substructure_create_from_sec_label(
sec_label_t *label)
{
private_traffic_selector_substructure_t *this;
this = (private_traffic_selector_substructure_t*)traffic_selector_substructure_create();
this->ts_type = TS_SECLABEL;
this->ts_data = chunk_clone(label->get_encoding(label));
this->payload_length += this->ts_data.len;
return &this->public;
}
@@ -13,6 +13,27 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/*
* Copyright (C) 2022 Tobias Brunner, codelabs GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* @defgroup traffic_selector_substructure traffic_selector_substructure
@@ -27,6 +48,7 @@ typedef struct traffic_selector_substructure_t traffic_selector_substructure_t;
#include <library.h>
#include <networking/host.h>
#include <selectors/traffic_selector.h>
#include <selectors/sec_label.h>
#include <encoding/payloads/payload.h>
/**
@@ -35,88 +57,29 @@ typedef struct traffic_selector_substructure_t traffic_selector_substructure_t;
* The TRAFFIC SELECTOR format is described in RFC section 3.13.1.
*/
struct traffic_selector_substructure_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Get the type of Traffic selector.
* Get a traffic_selector_t from this substructure if possible.
*
* @return type of traffic selector
* @warning the returned object must be destroyed after use
*
* @return contained traffic_selector_t (NULL if type mismatch)
*/
ts_type_t (*get_ts_type) (traffic_selector_substructure_t *this);
traffic_selector_t *(*get_traffic_selector)(traffic_selector_substructure_t *this);
/**
* Set the type of Traffic selector.
* Get a sec_label_t from this substructure if possible.
*
* @param ts_type type of traffic selector
* @warning the returned object must be destroyed after use
*
* @return contained sec_label_t (NULL if type mismatch)
*/
void (*set_ts_type) (traffic_selector_substructure_t *this,
ts_type_t ts_type);
/**
* Get the IP protocol ID of Traffic selector.
*
* @return type of traffic selector
*
*/
uint8_t (*get_protocol_id) (traffic_selector_substructure_t *this);
/**
* Set the IP protocol ID of Traffic selector
*
* @param protocol_id protocol ID of traffic selector
*/
void (*set_protocol_id) (traffic_selector_substructure_t *this,
uint8_t protocol_id);
/**
* Get the start port and address as host_t object.
*
* Returned host_t object has to get destroyed by the caller.
*
* @return start host as host_t object
*
*/
host_t *(*get_start_host) (traffic_selector_substructure_t *this);
/**
* Set the start port and address as host_t object.
*
* @param start_host start host as host_t object
*/
void (*set_start_host) (traffic_selector_substructure_t *this,
host_t *start_host);
/**
* Get the end port and address as host_t object.
*
* Returned host_t object has to get destroyed by the caller.
*
* @return end host as host_t object
*
*/
host_t *(*get_end_host) (traffic_selector_substructure_t *this);
/**
* Set the end port and address as host_t object.
*
* @param end_host end host as host_t object
*/
void (*set_end_host) (traffic_selector_substructure_t *this,
host_t *end_host);
/**
* Get a traffic_selector_t from this substructure.
*
* @warning traffic_selector_t must be destroyed after usage.
*
* @return contained traffic_selector_t
*/
traffic_selector_t *(*get_traffic_selector) (
traffic_selector_substructure_t *this);
sec_label_t *(*get_sec_label)(traffic_selector_substructure_t *this);
/**
* Destroys an traffic_selector_substructure_t object.
@@ -134,13 +97,21 @@ struct traffic_selector_substructure_t {
traffic_selector_substructure_t *traffic_selector_substructure_create(void);
/**
* Creates an initialized traffic selector substructure using
* the values from a traffic_selector_t.
* Creates a traffic selector substructure based on a traffic_selector_t.
*
* @param traffic_selector traffic_selector_t to use for initialization
* @param traffic_selector data to use
* @return traffic_selector_substructure_t object
*/
traffic_selector_substructure_t *traffic_selector_substructure_create_from_traffic_selector(
traffic_selector_t *traffic_selector);
/**
* Creates a traffic selector substructure based on a sec_label_t.
*
* @param label data to use
* @return traffic_selector_substructure_t object
*/
traffic_selector_substructure_t *traffic_selector_substructure_create_from_sec_label(
sec_label_t *label);
#endif /** TRAFFIC_SELECTOR_SUBSTRUCTURE_H_ @}*/