Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sebastian Schrader
Kea
Commits
d92767e4
Commit
d92767e4
authored
Mar 23, 2016
by
Francis Dupont
Browse files
[4268a] Rebased TokenPkt4 code
parent
3b5f6d63
Changes
4
Hide whitespace changes
Inline
Side-by-side
src/lib/eval/tests/context_unittest.cc
View file @
d92767e4
...
...
@@ -132,6 +132,51 @@ public:
}
}
/// @brief checks if the given token is Pkt4 of specified type
/// @param token token to be checked
/// @param type expected type of the Pkt4 field
void
checkTokenPkt4
(
const
TokenPtr
&
token
,
TokenPkt4
::
FieldType
type
)
{
ASSERT_TRUE
(
token
);
boost
::
shared_ptr
<
TokenPkt4
>
pkt
=
boost
::
dynamic_pointer_cast
<
TokenPkt4
>
(
token
);
ASSERT_TRUE
(
pkt
);
EXPECT_EQ
(
type
,
pkt
->
getType
());
}
/// @brief Test that verifies access to the DHCPv4 packet fields.
///
/// This test attempts to parse the expression, will check if the number
/// of tokens is exactly as expected and then will try to verify if the
/// first token represents the expected field in DHCPv4 packet.
///
/// @param expr expression to be parsed
/// @param exp_type expected field type to be parsed
/// @param exp_tokens expected number of tokens
void
testPkt4Field
(
std
::
string
expr
,
TokenPkt4
::
FieldType
exp_type
,
int
exp_tokens
)
{
EvalContext
eval
(
Option
::
V4
);
// Parse the expression.
try
{
parsed_
=
eval
.
parseString
(
expr
);
}
catch
(
const
EvalParseError
&
ex
)
{
FAIL
()
<<
"Exception thrown: "
<<
ex
.
what
();
return
;
}
// Parsing should succeed and return a token.
EXPECT_TRUE
(
parsed_
);
// There should be exactly the expected number of tokens.
ASSERT_EQ
(
exp_tokens
,
eval
.
expression
.
size
());
// Check that the first token is TokenPkt4 instance and has correct type.
checkTokenPkt4
(
eval
.
expression
.
at
(
0
),
exp_type
);
}
/// @brief checks if the given token is a substring operator
void
checkTokenSubstring
(
const
TokenPtr
&
token
)
{
ASSERT_TRUE
(
token
);
...
...
@@ -430,6 +475,41 @@ TEST_F(EvalContextTest, relay4Error) {
"<string>:1.1-6: relay4 can only be used in DHCPv4."
);
}
// Tests whether chaddr field in DHCPv4 can be accessed.
TEST_F
(
EvalContextTest
,
pkt4FieldChaddr
)
{
testPkt4Field
(
"pkt4.mac == 0x000102030405"
,
TokenPkt4
::
CHADDR
,
3
);
}
// Tests whether hlen field in DHCPv4 can be accessed.
TEST_F
(
EvalContextTest
,
pkt4FieldHlen
)
{
testPkt4Field
(
"pkt4.hlen == 0x6"
,
TokenPkt4
::
HLEN
,
3
);
}
// Tests whether htype field in DHCPv4 can be accessed.
TEST_F
(
EvalContextTest
,
pkt4FieldHtype
)
{
testPkt4Field
(
"pkt4.htype == 0x1"
,
TokenPkt4
::
HTYPE
,
3
);
}
// Tests whether ciaddr field in DHCPv4 can be accessed.
TEST_F
(
EvalContextTest
,
pkt4FieldCiaddr
)
{
testPkt4Field
(
"pkt4.ciaddr == 192.0.2.1"
,
TokenPkt4
::
CIADDR
,
3
);
}
// Tests whether giaddr field in DHCPv4 can be accessed.
TEST_F
(
EvalContextTest
,
pkt4FieldGiaddr
)
{
testPkt4Field
(
"pkt4.giaddr == 192.0.2.1"
,
TokenPkt4
::
GIADDR
,
3
);
}
// Tests whether yiaddr field in DHCPv4 can be accessed.
TEST_F
(
EvalContextTest
,
pkt4FieldYiaddr
)
{
testPkt4Field
(
"pkt4.yiaddr == 192.0.2.1"
,
TokenPkt4
::
YIADDR
,
3
);
}
// Tests whether siaddr field in DHCPv4 can be accessed.
TEST_F
(
EvalContextTest
,
pkt4FieldSiaddr
)
{
testPkt4Field
(
"pkt4.siaddr == 192.0.2.1"
,
TokenPkt4
::
SIADDR
,
3
);
}
// Test parsing of logical operators
TEST_F
(
EvalContextTest
,
logicalOps
)
{
// option.exists
...
...
@@ -588,6 +668,7 @@ TEST_F(EvalContextTest, scanErrors) {
checkError
(
"foo"
,
"<string>:1.1: Invalid character: f"
);
checkError
(
" bar"
,
"<string>:1.2: Invalid character: b"
);
checkError
(
"relay[12].hex == 'foo'"
,
"<string>:1.1: Invalid character: r"
);
checkError
(
"pkt4.ziaddr"
,
"<string>:1.6: Invalid character: z"
);
}
// Tests some scanner/parser error cases
...
...
src/lib/eval/tests/token_unittest.cc
View file @
d92767e4
...
...
@@ -20,6 +20,7 @@
using
namespace
std
;
using
namespace
isc
::
dhcp
;
using
namespace
isc
::
asiolink
;
namespace
{
...
...
@@ -603,6 +604,84 @@ TEST_F(TokenTest, relay4RAIOnly) {
EXPECT_EQ
(
"false"
,
values_
.
top
());
}
// Verifies if the DHCPv4 packet fields can be extracted.
TEST_F
(
TokenTest
,
pkt4Fields
)
{
pkt4_
->
setGiaddr
(
IOAddress
(
"192.0.2.1"
));
pkt4_
->
setCiaddr
(
IOAddress
(
"192.0.2.2"
));
pkt4_
->
setYiaddr
(
IOAddress
(
"192.0.2.3"
));
pkt4_
->
setSiaddr
(
IOAddress
(
"192.0.2.4"
));
// We're setting hardware address to uncommon (7 bytes rather than 6 and
// hardware type 123) HW address. We'll use it in hlen and htype checks.
HWAddrPtr
hw
(
new
HWAddr
(
HWAddr
::
fromText
(
"01:02:03:04:05:06:07"
,
123
)));
pkt4_
->
setHWAddr
(
hw
);
// Check hardware address field.
ASSERT_NO_THROW
(
t_
.
reset
(
new
TokenPkt4
(
TokenPkt4
::
CHADDR
)));
EXPECT_NO_THROW
(
t_
->
evaluate
(
*
pkt4_
,
values_
));
ASSERT_EQ
(
1
,
values_
.
size
());
uint8_t
expected_hw
[]
=
{
1
,
2
,
3
,
4
,
5
,
6
,
7
};
ASSERT_EQ
(
7
,
values_
.
top
().
size
());
EXPECT_EQ
(
0
,
memcmp
(
expected_hw
,
&
values_
.
top
()[
0
],
7
));
// Check hlen value field.
clearStack
();
ASSERT_NO_THROW
(
t_
.
reset
(
new
TokenPkt4
(
TokenPkt4
::
HLEN
)));
EXPECT_NO_THROW
(
t_
->
evaluate
(
*
pkt4_
,
values_
));
ASSERT_EQ
(
1
,
values_
.
size
());
ASSERT_EQ
(
1
,
values_
.
top
().
size
());
EXPECT_EQ
(
7
,
static_cast
<
uint8_t
>
(
values_
.
top
()[
0
]));
// Check htype value.
clearStack
();
ASSERT_NO_THROW
(
t_
.
reset
(
new
TokenPkt4
(
TokenPkt4
::
HTYPE
)));
EXPECT_NO_THROW
(
t_
->
evaluate
(
*
pkt4_
,
values_
));
ASSERT_EQ
(
1
,
values_
.
size
());
ASSERT_EQ
(
1
,
values_
.
top
().
size
());
EXPECT_EQ
(
123
,
static_cast
<
uint8_t
>
(
values_
.
top
()[
0
]));
// Check giaddr value.
clearStack
();
ASSERT_NO_THROW
(
t_
.
reset
(
new
TokenPkt4
(
TokenPkt4
::
GIADDR
)));
EXPECT_NO_THROW
(
t_
->
evaluate
(
*
pkt4_
,
values_
));
ASSERT_EQ
(
1
,
values_
.
size
());
uint8_t
expected_addr
[]
=
{
192
,
0
,
2
,
1
};
ASSERT_EQ
(
4
,
values_
.
top
().
size
());
EXPECT_EQ
(
0
,
memcmp
(
expected_addr
,
&
values_
.
top
()[
0
],
4
));
// Check ciaddr value.
clearStack
();
ASSERT_NO_THROW
(
t_
.
reset
(
new
TokenPkt4
(
TokenPkt4
::
CIADDR
)));
EXPECT_NO_THROW
(
t_
->
evaluate
(
*
pkt4_
,
values_
));
ASSERT_EQ
(
1
,
values_
.
size
());
expected_addr
[
3
]
=
2
;
ASSERT_EQ
(
4
,
values_
.
top
().
size
());
EXPECT_EQ
(
0
,
memcmp
(
expected_addr
,
&
values_
.
top
()[
0
],
4
));
// Check yiaddr value.
clearStack
();
ASSERT_NO_THROW
(
t_
.
reset
(
new
TokenPkt4
(
TokenPkt4
::
YIADDR
)));
EXPECT_NO_THROW
(
t_
->
evaluate
(
*
pkt4_
,
values_
));
ASSERT_EQ
(
1
,
values_
.
size
());
expected_addr
[
3
]
=
3
;
ASSERT_EQ
(
4
,
values_
.
top
().
size
());
EXPECT_EQ
(
0
,
memcmp
(
expected_addr
,
&
values_
.
top
()[
0
],
4
));
// Check siaddr value.
clearStack
();
ASSERT_NO_THROW
(
t_
.
reset
(
new
TokenPkt4
(
TokenPkt4
::
SIADDR
)));
EXPECT_NO_THROW
(
t_
->
evaluate
(
*
pkt4_
,
values_
));
ASSERT_EQ
(
1
,
values_
.
size
());
expected_addr
[
3
]
=
4
;
ASSERT_EQ
(
4
,
values_
.
top
().
size
());
EXPECT_EQ
(
0
,
memcmp
(
expected_addr
,
&
values_
.
top
()[
0
],
4
));
// Check a DHCPv6 packet throws.
clearStack
();
ASSERT_NO_THROW
(
t_
.
reset
(
new
TokenPkt4
(
TokenPkt4
::
HLEN
)));
EXPECT_THROW
(
t_
->
evaluate
(
*
pkt6_
,
values_
),
EvalTypeError
);
}
// This test checks if a token representing an == operator is able to
// compare two values (with incorrectly built stack).
TEST_F
(
TokenTest
,
optionEqualInvalid
)
{
...
...
src/lib/eval/token.cc
View file @
d92767e4
...
...
@@ -8,6 +8,7 @@
#include
<eval/eval_log.h>
#include
<util/encode/hex.h>
#include
<asiolink/io_address.h>
#include
<dhcp/pkt4.h>
#include
<boost/lexical_cast.hpp>
#include
<cstring>
#include
<string>
...
...
@@ -123,6 +124,69 @@ OptionPtr TokenRelay4Option::getOption(const Pkt& pkt) {
return
(
rai
->
getOption
(
option_code_
));
}
void
TokenPkt4
::
evaluate
(
const
Pkt
&
pkt
,
ValueStack
&
values
)
{
vector
<
uint8_t
>
binary
;
try
{
// Check if it's a Pkt4. If it's not, the dynamic_cast will throw
// std::bad_cast (failed dynamic_cast returns NULL for pointers and
// throws for references).
const
Pkt4
&
pkt4
=
dynamic_cast
<
const
Pkt4
&>
(
pkt
);
switch
(
type_
)
{
case
CHADDR
:
{
HWAddrPtr
hwaddr
=
pkt4
.
getHWAddr
();
if
(
!
hwaddr
)
{
// This should never happen. Every Pkt4 should always have
// a hardware address.
isc_throw
(
EvalTypeError
,
"Packet does not have hardware address"
);
}
binary
=
hwaddr
->
hwaddr_
;
break
;
}
case
GIADDR
:
binary
=
pkt4
.
getGiaddr
().
toBytes
();
break
;
case
CIADDR
:
binary
=
pkt4
.
getCiaddr
().
toBytes
();
break
;
case
YIADDR
:
binary
=
pkt4
.
getYiaddr
().
toBytes
();
break
;
case
SIADDR
:
binary
=
pkt4
.
getSiaddr
().
toBytes
();
break
;
case
HLEN
:
binary
.
assign
(
1
,
pkt4
.
getHlen
());
break
;
case
HTYPE
:
binary
.
assign
(
1
,
pkt4
.
getHtype
());
break
;
default:
isc_throw
(
EvalTypeError
,
"Bad field specified: "
<<
static_cast
<
int
>
(
type_
)
);
}
}
catch
(
const
std
::
bad_cast
&
)
{
isc_throw
(
EvalTypeError
,
"Specified packet is not a Pkt4"
);
}
string
value
;
value
.
resize
(
binary
.
size
());
if
(
!
binary
.
empty
())
{
memmove
(
&
value
[
0
],
&
binary
[
0
],
binary
.
size
());
}
values
.
push
(
value
);
}
void
TokenEqual
::
evaluate
(
const
Pkt
&
/*pkt*/
,
ValueStack
&
values
)
{
...
...
src/lib/eval/token.h
View file @
d92767e4
...
...
@@ -288,6 +288,61 @@ protected:
virtual
OptionPtr
getOption
(
const
Pkt
&
pkt
);
};
/// @brief Token that represents fields of a DHCPv4 packet.
///
/// For example in the expression pkt4.chaddr == 0x0102030405
/// this token represents the pkt4.chaddr expression.
///
/// Currently supported fields are:
/// - chaddr (client hardware address, hlen [0..16] octets)
/// - giaddr (relay agent IP address, 4 octets)
/// - ciaddr (client IP address, 4 octets)
/// - yiaddr ('your' (client) IP address, 4 octets)
/// - siaddr (next server IP address, 4 octets)
/// - hlen (hardware address length, 1 octet)
/// - htype (hardware address type, 1 octet)
class
TokenPkt4
:
public
Token
{
public:
/// @brief enum value that determines the field.
enum
FieldType
{
CHADDR
,
///< chaddr field (up to 16 bytes link-layer address)
GIADDR
,
///< giaddr (IPv4 address)
CIADDR
,
///< ciaddr (IPv4 address)
YIADDR
,
///< yiaddr (IPv4 address)
SIADDR
,
///< siaddr (IPv4 address)
HLEN
,
///< hlen (hardware address length)
HTYPE
///< htype (hardware address type)
};
/// @brief Constructor (does nothing)
TokenPkt4
(
const
FieldType
type
)
:
type_
(
type
)
{}
/// @brief Gets a value from the specified packet.
///
/// Evaluation uses fields available in the packet. It does not require
/// any values to be present on the stack.
///
/// @throw EvalTypeError when called for DHCPv6 packet
///
/// @param pkt - fields will be extracted from here
/// @param values - stack of values (1 result will be pushed)
void
evaluate
(
const
Pkt
&
pkt
,
ValueStack
&
values
);
/// @brief Returns field type
///
/// This method is used only in tests.
/// @return type of the field.
FieldType
getType
()
{
return
(
type_
);
}
private:
/// @brief Specifies field of the DHCPv4 packet
FieldType
type_
;
};
/// @brief Token that represents equality operator (compares two other tokens)
///
/// For example in the expression option[vendor-class].text == "MSFT"
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment