2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-30 13:37:55 +00:00

[master] Finished merge of trac4232a (IP address literal)

This commit is contained in:
Francis Dupont 2016-03-18 11:04:02 +01:00
commit 7917d94e55
14 changed files with 692 additions and 454 deletions

View File

@ -1,3 +1,8 @@
1090. [func] fdupont
Added support for IP address (IPv4 and IPv6) literals in
classification expressions.
(Trac #4232, git xxx)
1089. [func] fdupont 1089. [func] fdupont
Added relay4[X].exists method in classifications that checks Added relay4[X].exists method in classifications that checks
whether a sub-option is present in theDHCPv4 RAI (Relay Agent whether a sub-option is present in theDHCPv4 RAI (Relay Agent

View File

@ -159,6 +159,7 @@
<tbody> <tbody>
<row><entry>String</entry><entry>'example'</entry><entry>A string</entry></row> <row><entry>String</entry><entry>'example'</entry><entry>A string</entry></row>
<row><entry>Hex String</entry><entry>0XABCD</entry><entry>A hexadecimal string</entry></row> <row><entry>Hex String</entry><entry>0XABCD</entry><entry>A hexadecimal string</entry></row>
<row><entry>IP Address</entry><entry>10.0.0.1</entry><entry>An IP address</entry></row>
<row><entry>Integer</entry><entry>123</entry><entry>An integer value</entry></row> <row><entry>Integer</entry><entry>123</entry><entry>An integer value</entry></row>
<!-- Text option not fully defined yet, leave it out <!-- Text option not fully defined yet, leave it out
<row><entry>Option Text</entry><entry>option[code].text</entry><entry>The value of the option with code "code" from the packet as text</entry></row> <row><entry>Option Text</entry><entry>option[code].text</entry><entry>The value of the option with code "code" from the packet as text</entry></row>
@ -177,6 +178,11 @@ sub-option with code "code" from the DHCPv4 Relay Agent Information option
&quot;0&quot; is prepended to it. &quot;0&quot; is prepended to it.
</para> </para>
<para>
IP addresses are converted into strings of length 4 or 16. IPv4, IPv6,
and IPv4 embedded IPv6 (e.g., IPv4 mapped IPv6) addresses are supported.
</para>
<para> <para>
Integers in the expression are converted to strings Integers in the expression are converted to strings
when the expression is read into Kea. when the expression is read into Kea.

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@
#include <string> #include <string>
#include <eval/eval_context.h> #include <eval/eval_context.h>
#include <eval/parser.h> #include <eval/parser.h>
#include <asiolink/io_address.h>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
// Work around an incompatibility in flex (at least versions // Work around an incompatibility in flex (at least versions
@ -56,10 +57,13 @@ static isc::eval::location loc;
%option yylineno %option yylineno
/* These are not token expressions yet, just convenience expressions that /* These are not token expressions yet, just convenience expressions that
can be used during actual token definitions. */ can be used during actual token definitions. Note some can match
incorrect inputs (e.g., IP addresses) which must be checked. */
int \-?[0-9]+ int \-?[0-9]+
hex [0-9a-fA-F]+ hex [0-9a-fA-F]+
blank [ \t] blank [ \t]
addr4 [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+
addr6 [0-9a-fA-F]*\:[0-9a-fA-F]*\:[0-9a-fA-F:.]*
%{ %{
// This code run each time a pattern is matched. It updates the location // This code run each time a pattern is matched. It updates the location
@ -122,6 +126,20 @@ blank [ \t]
return isc::eval::EvalParser::make_OPTION_NAME(yytext, loc); return isc::eval::EvalParser::make_OPTION_NAME(yytext, loc);
} }
{addr4}|{addr6} {
// IPv4 or IPv6 address
std::string tmp(yytext);
// Some incorrect addresses can match so we have to check.
try {
isc::asiolink::IOAddress ip(tmp);
} catch (...) {
driver.error(loc, "Failed to convert " + tmp + " to an IP address.");
}
return isc::eval::EvalParser::make_IP_ADDRESS(yytext, loc);
}
"==" return isc::eval::EvalParser::make_EQUAL(loc); "==" return isc::eval::EvalParser::make_EQUAL(loc);
"option" return isc::eval::EvalParser::make_OPTION(loc); "option" return isc::eval::EvalParser::make_OPTION(loc);
"relay4" return isc::eval::EvalParser::make_RELAY4(loc); "relay4" return isc::eval::EvalParser::make_RELAY4(loc);

View File

@ -40,9 +40,9 @@
# include "position.hh" # include "position.hh"
#line 13 "parser.yy" // location.cc:296 #line 13 "parser.yy" // location.cc:337
namespace isc { namespace eval { namespace isc { namespace eval {
#line 46 "location.hh" // location.cc:296 #line 46 "location.hh" // location.cc:337
/// Abstract a location. /// Abstract a location.
class location class location
{ {
@ -186,7 +186,7 @@ namespace isc { namespace eval {
return ostr; return ostr;
} }
#line 13 "parser.yy" // location.cc:296 #line 13 "parser.yy" // location.cc:337
} } // isc::eval } } // isc::eval
#line 192 "location.hh" // location.cc:296 #line 192 "location.hh" // location.cc:337
#endif // !YY_YY_LOCATION_HH_INCLUDED #endif // !YY_YY_LOCATION_HH_INCLUDED

View File

@ -251,7 +251,7 @@ namespace isc { namespace eval {
{ {
switch (that.type_get ()) switch (that.type_get ())
{ {
case 30: // option_repr_type case 31: // option_repr_type
value.move< TokenOption::RepresentationType > (that.value); value.move< TokenOption::RepresentationType > (that.value);
break; break;
@ -259,10 +259,11 @@ namespace isc { namespace eval {
case 22: // "integer" case 22: // "integer"
case 23: // "constant hexstring" case 23: // "constant hexstring"
case 24: // "option name" case 24: // "option name"
case 25: // "ip address"
value.move< std::string > (that.value); value.move< std::string > (that.value);
break; break;
case 29: // option_code case 30: // option_code
value.move< uint16_t > (that.value); value.move< uint16_t > (that.value);
break; break;
@ -281,7 +282,7 @@ namespace isc { namespace eval {
state = that.state; state = that.state;
switch (that.type_get ()) switch (that.type_get ())
{ {
case 30: // option_repr_type case 31: // option_repr_type
value.copy< TokenOption::RepresentationType > (that.value); value.copy< TokenOption::RepresentationType > (that.value);
break; break;
@ -289,10 +290,11 @@ namespace isc { namespace eval {
case 22: // "integer" case 22: // "integer"
case 23: // "constant hexstring" case 23: // "constant hexstring"
case 24: // "option name" case 24: // "option name"
case 25: // "ip address"
value.copy< std::string > (that.value); value.copy< std::string > (that.value);
break; break;
case 29: // option_code case 30: // option_code
value.copy< uint16_t > (that.value); value.copy< uint16_t > (that.value);
break; break;
@ -334,44 +336,51 @@ namespace isc { namespace eval {
{ {
case 21: // "constant string" case 21: // "constant string"
#line 72 "parser.yy" // lalr1.cc:636 #line 73 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); } { yyoutput << yysym.value.template as< std::string > (); }
#line 340 "parser.cc" // lalr1.cc:636 #line 342 "parser.cc" // lalr1.cc:636
break; break;
case 22: // "integer" case 22: // "integer"
#line 72 "parser.yy" // lalr1.cc:636 #line 73 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); } { yyoutput << yysym.value.template as< std::string > (); }
#line 347 "parser.cc" // lalr1.cc:636 #line 349 "parser.cc" // lalr1.cc:636
break; break;
case 23: // "constant hexstring" case 23: // "constant hexstring"
#line 72 "parser.yy" // lalr1.cc:636 #line 73 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); } { yyoutput << yysym.value.template as< std::string > (); }
#line 354 "parser.cc" // lalr1.cc:636 #line 356 "parser.cc" // lalr1.cc:636
break; break;
case 24: // "option name" case 24: // "option name"
#line 72 "parser.yy" // lalr1.cc:636 #line 73 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); } { yyoutput << yysym.value.template as< std::string > (); }
#line 361 "parser.cc" // lalr1.cc:636 #line 363 "parser.cc" // lalr1.cc:636
break; break;
case 29: // option_code case 25: // "ip address"
#line 72 "parser.yy" // lalr1.cc:636 #line 73 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
#line 370 "parser.cc" // lalr1.cc:636
break;
case 30: // option_code
#line 73 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< uint16_t > (); } { yyoutput << yysym.value.template as< uint16_t > (); }
#line 368 "parser.cc" // lalr1.cc:636 #line 377 "parser.cc" // lalr1.cc:636
break; break;
case 30: // option_repr_type case 31: // option_repr_type
#line 72 "parser.yy" // lalr1.cc:636 #line 73 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< TokenOption::RepresentationType > (); } { yyoutput << yysym.value.template as< TokenOption::RepresentationType > (); }
#line 375 "parser.cc" // lalr1.cc:636 #line 384 "parser.cc" // lalr1.cc:636
break; break;
@ -571,7 +580,7 @@ namespace isc { namespace eval {
when using variants. */ when using variants. */
switch (yyr1_[yyn]) switch (yyr1_[yyn])
{ {
case 30: // option_repr_type case 31: // option_repr_type
yylhs.value.build< TokenOption::RepresentationType > (); yylhs.value.build< TokenOption::RepresentationType > ();
break; break;
@ -579,10 +588,11 @@ namespace isc { namespace eval {
case 22: // "integer" case 22: // "integer"
case 23: // "constant hexstring" case 23: // "constant hexstring"
case 24: // "option name" case 24: // "option name"
case 25: // "ip address"
yylhs.value.build< std::string > (); yylhs.value.build< std::string > ();
break; break;
case 29: // option_code case 30: // option_code
yylhs.value.build< uint16_t > (); yylhs.value.build< uint16_t > ();
break; break;
@ -604,52 +614,52 @@ namespace isc { namespace eval {
switch (yyn) switch (yyn)
{ {
case 4: case 4:
#line 86 "parser.yy" // lalr1.cc:859 #line 87 "parser.yy" // lalr1.cc:859
{ {
TokenPtr neg(new TokenNot()); TokenPtr neg(new TokenNot());
ctx.expression.push_back(neg); ctx.expression.push_back(neg);
} }
#line 613 "parser.cc" // lalr1.cc:859 #line 623 "parser.cc" // lalr1.cc:859
break; break;
case 5: case 5:
#line 91 "parser.yy" // lalr1.cc:859 #line 92 "parser.yy" // lalr1.cc:859
{ {
TokenPtr neg(new TokenAnd()); TokenPtr neg(new TokenAnd());
ctx.expression.push_back(neg); ctx.expression.push_back(neg);
} }
#line 622 "parser.cc" // lalr1.cc:859 #line 632 "parser.cc" // lalr1.cc:859
break; break;
case 6: case 6:
#line 96 "parser.yy" // lalr1.cc:859 #line 97 "parser.yy" // lalr1.cc:859
{ {
TokenPtr neg(new TokenOr()); TokenPtr neg(new TokenOr());
ctx.expression.push_back(neg); ctx.expression.push_back(neg);
} }
#line 631 "parser.cc" // lalr1.cc:859 #line 641 "parser.cc" // lalr1.cc:859
break; break;
case 7: case 7:
#line 101 "parser.yy" // lalr1.cc:859 #line 102 "parser.yy" // lalr1.cc:859
{ {
TokenPtr eq(new TokenEqual()); TokenPtr eq(new TokenEqual());
ctx.expression.push_back(eq); ctx.expression.push_back(eq);
} }
#line 640 "parser.cc" // lalr1.cc:859 #line 650 "parser.cc" // lalr1.cc:859
break; break;
case 8: case 8:
#line 106 "parser.yy" // lalr1.cc:859 #line 107 "parser.yy" // lalr1.cc:859
{ {
TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), TokenOption::EXISTS)); TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), TokenOption::EXISTS));
ctx.expression.push_back(opt); ctx.expression.push_back(opt);
} }
#line 649 "parser.cc" // lalr1.cc:859 #line 659 "parser.cc" // lalr1.cc:859
break; break;
case 9: case 9:
#line 111 "parser.yy" // lalr1.cc:859 #line 112 "parser.yy" // lalr1.cc:859
{ {
switch (ctx.getUniverse()) { switch (ctx.getUniverse()) {
case Option::V4: case Option::V4:
@ -669,38 +679,47 @@ namespace isc { namespace eval {
error(yystack_[5].location, "relay4 can only be used in DHCPv4."); error(yystack_[5].location, "relay4 can only be used in DHCPv4.");
} }
} }
#line 673 "parser.cc" // lalr1.cc:859 #line 683 "parser.cc" // lalr1.cc:859
break; break;
case 10: case 10:
#line 133 "parser.yy" // lalr1.cc:859 #line 134 "parser.yy" // lalr1.cc:859
{ {
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str); ctx.expression.push_back(str);
} }
#line 682 "parser.cc" // lalr1.cc:859 #line 692 "parser.cc" // lalr1.cc:859
break; break;
case 11: case 11:
#line 138 "parser.yy" // lalr1.cc:859 #line 139 "parser.yy" // lalr1.cc:859
{ {
TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ())); TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(hex); ctx.expression.push_back(hex);
} }
#line 691 "parser.cc" // lalr1.cc:859 #line 701 "parser.cc" // lalr1.cc:859
break; break;
case 12: case 12:
#line 143 "parser.yy" // lalr1.cc:859 #line 144 "parser.yy" // lalr1.cc:859
{
TokenPtr ip(new TokenIpAddress(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(ip);
}
#line 710 "parser.cc" // lalr1.cc:859
break;
case 13:
#line 149 "parser.yy" // lalr1.cc:859
{ {
TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), yystack_[0].value.as< TokenOption::RepresentationType > ())); TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), yystack_[0].value.as< TokenOption::RepresentationType > ()));
ctx.expression.push_back(opt); ctx.expression.push_back(opt);
} }
#line 700 "parser.cc" // lalr1.cc:859 #line 719 "parser.cc" // lalr1.cc:859
break; break;
case 13: case 14:
#line 148 "parser.yy" // lalr1.cc:859 #line 154 "parser.yy" // lalr1.cc:859
{ {
switch (ctx.getUniverse()) { switch (ctx.getUniverse()) {
case Option::V4: case Option::V4:
@ -720,88 +739,88 @@ namespace isc { namespace eval {
error(yystack_[5].location, "relay4 can only be used in DHCPv4."); error(yystack_[5].location, "relay4 can only be used in DHCPv4.");
} }
} }
#line 724 "parser.cc" // lalr1.cc:859 #line 743 "parser.cc" // lalr1.cc:859
break; break;
case 14: case 15:
#line 168 "parser.yy" // lalr1.cc:859 #line 174 "parser.yy" // lalr1.cc:859
{ {
TokenPtr sub(new TokenSubstring()); TokenPtr sub(new TokenSubstring());
ctx.expression.push_back(sub); ctx.expression.push_back(sub);
} }
#line 733 "parser.cc" // lalr1.cc:859 #line 752 "parser.cc" // lalr1.cc:859
break; break;
case 15: case 16:
#line 173 "parser.yy" // lalr1.cc:859 #line 179 "parser.yy" // lalr1.cc:859
{ {
TokenPtr conc(new TokenConcat()); TokenPtr conc(new TokenConcat());
ctx.expression.push_back(conc); ctx.expression.push_back(conc);
} }
#line 742 "parser.cc" // lalr1.cc:859 #line 761 "parser.cc" // lalr1.cc:859
break;
case 16:
#line 180 "parser.yy" // lalr1.cc:859
{
yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location);
}
#line 750 "parser.cc" // lalr1.cc:859
break; break;
case 17: case 17:
#line 184 "parser.yy" // lalr1.cc:859 #line 186 "parser.yy" // lalr1.cc:859
{ {
yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location); yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location);
} }
#line 758 "parser.cc" // lalr1.cc:859 #line 769 "parser.cc" // lalr1.cc:859
break; break;
case 18: case 18:
#line 190 "parser.yy" // lalr1.cc:859 #line 190 "parser.yy" // lalr1.cc:859
{ {
yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL; yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location);
} }
#line 766 "parser.cc" // lalr1.cc:859 #line 777 "parser.cc" // lalr1.cc:859
break; break;
case 19: case 19:
#line 194 "parser.yy" // lalr1.cc:859 #line 196 "parser.yy" // lalr1.cc:859
{ {
yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL; yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL;
} }
#line 774 "parser.cc" // lalr1.cc:859 #line 785 "parser.cc" // lalr1.cc:859
break; break;
case 20: case 20:
#line 200 "parser.yy" // lalr1.cc:859 #line 200 "parser.yy" // lalr1.cc:859
{ {
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL;
ctx.expression.push_back(str); }
} #line 793 "parser.cc" // lalr1.cc:859
#line 783 "parser.cc" // lalr1.cc:859
break; break;
case 21: case 21:
#line 207 "parser.yy" // lalr1.cc:859 #line 206 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str);
}
#line 802 "parser.cc" // lalr1.cc:859
break;
case 22:
#line 213 "parser.yy" // lalr1.cc:859
{ {
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str); ctx.expression.push_back(str);
} }
#line 792 "parser.cc" // lalr1.cc:859 #line 811 "parser.cc" // lalr1.cc:859
break; break;
case 22: case 23:
#line 212 "parser.yy" // lalr1.cc:859 #line 218 "parser.yy" // lalr1.cc:859
{ {
TokenPtr str(new TokenString("all")); TokenPtr str(new TokenString("all"));
ctx.expression.push_back(str); ctx.expression.push_back(str);
} }
#line 801 "parser.cc" // lalr1.cc:859 #line 820 "parser.cc" // lalr1.cc:859
break; break;
#line 805 "parser.cc" // lalr1.cc:859 #line 824 "parser.cc" // lalr1.cc:859
default: default:
break; break;
} }
@ -1063,91 +1082,89 @@ namespace isc { namespace eval {
const signed char const signed char
EvalParser::yypact_[] = EvalParser::yypact_[] =
{ {
-1, -1, -1, 1, 10, 28, 36, -29, -29, 32, -1, -1, -1, 24, 27, 18, 37, -29, -29, -29,
0, 41, 29, -29, -7, -7, 17, 17, -29, -1, 50, 6, 43, 11, -29, 10, 10, 16, 16, -29,
-1, 17, -29, -29, -29, 38, 39, 42, 43, 37, -1, -1, 16, -29, -29, -29, 40, 41, 44, 45,
40, -29, 46, -29, 44, 45, -7, -7, 47, 17, 35, 38, -29, 52, -29, 46, 47, 10, 10, 39,
27, 30, 48, 49, -29, 51, 58, -29, -29, -29, 16, 28, 31, 51, 53, -29, 48, 58, -29, -29,
-29, -29, -29, 50, 52, -4, -29, 33, 33, -29, -29, -29, -29, -29, 55, 56, -15, -29, 34, 34,
-29, 60, -29 -29, -29, 60, -29
}; };
const unsigned char const unsigned char
EvalParser::yydefact_[] = EvalParser::yydefact_[] =
{ {
0, 0, 0, 0, 0, 0, 0, 10, 11, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12,
2, 0, 0, 4, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 4, 0, 0, 0, 0, 1,
0, 0, 3, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 3, 17, 18, 0, 0, 0, 0,
0, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 7, 0, 0, 0, 0, 0,
0, 0, 0, 0, 20, 0, 0, 18, 19, 8, 0, 0, 0, 0, 0, 21, 0, 0, 19, 20,
12, 9, 13, 0, 0, 0, 15, 0, 0, 22, 8, 13, 9, 14, 0, 0, 0, 16, 0, 0,
21, 0, 14 23, 22, 0, 15
}; };
const signed char const signed char
EvalParser::yypgoto_[] = EvalParser::yypgoto_[] =
{ {
-29, -29, 9, -16, -12, -28, -29, -29 -29, -29, 9, -17, -10, -28, -29, -29
}; };
const signed char const signed char
EvalParser::yydefgoto_[] = EvalParser::yydefgoto_[] =
{ {
-1, 9, 10, 11, 25, 50, 45, 61 -1, 10, 11, 12, 26, 51, 46, 62
}; };
const unsigned char const unsigned char
EvalParser::yytable_[] = EvalParser::yytable_[] =
{ {
29, 30, 1, 26, 2, 33, 19, 20, 3, 4, 30, 31, 1, 60, 2, 34, 27, 61, 3, 4,
12, 13, 14, 52, 59, 23, 5, 24, 60, 6, 13, 14, 20, 21, 53, 23, 5, 20, 21, 6,
7, 15, 8, 46, 42, 43, 27, 28, 31, 32, 7, 17, 8, 47, 9, 28, 29, 43, 44, 32,
52, 16, 18, 22, 5, 19, 20, 6, 7, 17, 33, 53, 24, 5, 25, 15, 6, 7, 16, 8,
8, 47, 48, 49, 47, 48, 51, 47, 48, 21, 18, 9, 48, 49, 50, 48, 49, 52, 48, 49,
34, 35, 19, 36, 37, 0, 38, 40, 41, 39, 19, 22, 35, 36, 39, 37, 38, 40, 20, 41,
53, 54, 56, 57, 62, 58, 0, 0, 0, 44, 42, 45, 57, 54, 63, 55, 0, 56, 58, 59
55
}; };
const signed char const signed char
EvalParser::yycheck_[] = EvalParser::yycheck_[] =
{ {
16, 17, 3, 15, 5, 21, 6, 7, 9, 10, 17, 18, 3, 18, 5, 22, 16, 22, 9, 10,
1, 2, 11, 41, 18, 22, 17, 24, 22, 20, 1, 2, 6, 7, 42, 4, 17, 6, 7, 20,
21, 11, 23, 39, 36, 37, 9, 10, 19, 20, 21, 3, 23, 40, 25, 9, 10, 37, 38, 20,
58, 3, 0, 4, 17, 6, 7, 20, 21, 3, 21, 59, 22, 17, 24, 11, 20, 21, 11, 23,
23, 14, 15, 16, 14, 15, 16, 14, 15, 8, 3, 25, 14, 15, 16, 14, 15, 16, 14, 15,
12, 12, 6, 11, 11, -1, 19, 13, 13, 19, 0, 8, 12, 12, 19, 11, 11, 19, 6, 13,
12, 12, 4, 13, 4, 13, -1, -1, -1, 22, 13, 22, 4, 12, 4, 12, -1, 19, 13, 13
19
}; };
const unsigned char const unsigned char
EvalParser::yystos_[] = EvalParser::yystos_[] =
{ {
0, 3, 5, 9, 10, 17, 20, 21, 23, 26, 0, 3, 5, 9, 10, 17, 20, 21, 23, 25,
27, 28, 27, 27, 11, 11, 3, 3, 0, 6, 27, 28, 29, 28, 28, 11, 11, 3, 3, 0,
7, 8, 4, 22, 24, 29, 29, 9, 10, 28, 6, 7, 8, 4, 22, 24, 30, 30, 9, 10,
28, 27, 27, 28, 12, 12, 11, 11, 19, 19, 29, 29, 28, 28, 29, 12, 12, 11, 11, 19,
13, 13, 29, 29, 22, 31, 28, 14, 15, 16, 19, 13, 13, 30, 30, 22, 32, 29, 14, 15,
30, 16, 30, 12, 12, 19, 4, 13, 13, 18, 16, 31, 16, 31, 12, 12, 19, 4, 13, 13,
22, 32, 4 18, 22, 33, 4
}; };
const unsigned char const unsigned char
EvalParser::yyr1_[] = EvalParser::yyr1_[] =
{ {
0, 25, 26, 27, 27, 27, 27, 27, 27, 27, 0, 26, 27, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 29, 29, 30, 30, 29, 29, 29, 29, 29, 29, 29, 30, 30, 31,
31, 32, 32 31, 32, 33, 33
}; };
const unsigned char const unsigned char
EvalParser::yyr2_[] = EvalParser::yyr2_[] =
{ {
0, 2, 1, 3, 2, 3, 3, 3, 6, 6, 0, 2, 1, 3, 2, 3, 3, 3, 6, 6,
1, 1, 6, 6, 8, 6, 1, 1, 1, 1, 1, 1, 1, 6, 6, 8, 6, 1, 1, 1,
1, 1, 1 1, 1, 1, 1
}; };
@ -1161,18 +1178,18 @@ namespace isc { namespace eval {
"\"and\"", "\"or\"", "\"==\"", "\"option\"", "\"relay4\"", "\"[\"", "\"and\"", "\"or\"", "\"==\"", "\"option\"", "\"relay4\"", "\"[\"",
"\"]\"", "\".\"", "\"text\"", "\"hex\"", "\"exists\"", "\"substring\"", "\"]\"", "\".\"", "\"text\"", "\"hex\"", "\"exists\"", "\"substring\"",
"\"all\"", "\",\"", "\"concat\"", "\"constant string\"", "\"integer\"", "\"all\"", "\",\"", "\"concat\"", "\"constant string\"", "\"integer\"",
"\"constant hexstring\"", "\"option name\"", "$accept", "expression", "\"constant hexstring\"", "\"option name\"", "\"ip address\"", "$accept",
"bool_expr", "string_expr", "option_code", "option_repr_type", "expression", "bool_expr", "string_expr", "option_code",
"start_expr", "length_expr", YY_NULLPTR "option_repr_type", "start_expr", "length_expr", YY_NULLPTR
}; };
#if YYDEBUG #if YYDEBUG
const unsigned char const unsigned char
EvalParser::yyrline_[] = EvalParser::yyrline_[] =
{ {
0, 81, 81, 84, 85, 90, 95, 100, 105, 110, 0, 82, 82, 85, 86, 91, 96, 101, 106, 111,
132, 137, 142, 147, 167, 172, 179, 183, 189, 193, 133, 138, 143, 148, 153, 173, 178, 185, 189, 195,
199, 206, 211 199, 205, 212, 217
}; };
// Print the state stack on the debug stream. // Print the state stack on the debug stream.
@ -1207,8 +1224,8 @@ namespace isc { namespace eval {
#line 13 "parser.yy" // lalr1.cc:1167 #line 13 "parser.yy" // lalr1.cc:1167
} } // isc::eval } } // isc::eval
#line 1211 "parser.cc" // lalr1.cc:1167 #line 1228 "parser.cc" // lalr1.cc:1167
#line 218 "parser.yy" // lalr1.cc:1168 #line 224 "parser.yy" // lalr1.cc:1168
void void
isc::eval::EvalParser::error(const location_type& loc, isc::eval::EvalParser::error(const location_type& loc,

View File

@ -40,7 +40,7 @@
#ifndef YY_YY_PARSER_H_INCLUDED #ifndef YY_YY_PARSER_H_INCLUDED
# define YY_YY_PARSER_H_INCLUDED # define YY_YY_PARSER_H_INCLUDED
// // "%code requires" blocks. // // "%code requires" blocks.
#line 16 "parser.yy" // lalr1.cc:377 #line 16 "parser.yy" // lalr1.cc:392
#include <string> #include <string>
#include <eval/token.h> #include <eval/token.h>
@ -51,7 +51,7 @@
using namespace isc::dhcp; using namespace isc::dhcp;
using namespace isc::eval; using namespace isc::eval;
#line 55 "parser.h" // lalr1.cc:377 #line 55 "parser.h" // lalr1.cc:392
# include <cassert> # include <cassert>
# include <cstdlib> // std::abort # include <cstdlib> // std::abort
@ -126,9 +126,9 @@ using namespace isc::eval;
# define YYDEBUG 1 # define YYDEBUG 1
#endif #endif
#line 13 "parser.yy" // lalr1.cc:377 #line 13 "parser.yy" // lalr1.cc:392
namespace isc { namespace eval { namespace isc { namespace eval {
#line 132 "parser.h" // lalr1.cc:377 #line 132 "parser.h" // lalr1.cc:392
@ -302,6 +302,7 @@ namespace isc { namespace eval {
// "integer" // "integer"
// "constant hexstring" // "constant hexstring"
// "option name" // "option name"
// "ip address"
char dummy2[sizeof(std::string)]; char dummy2[sizeof(std::string)];
// option_code // option_code
@ -350,7 +351,8 @@ namespace isc { namespace eval {
TOKEN_STRING = 276, TOKEN_STRING = 276,
TOKEN_INTEGER = 277, TOKEN_INTEGER = 277,
TOKEN_HEXSTRING = 278, TOKEN_HEXSTRING = 278,
TOKEN_OPTION_NAME = 279 TOKEN_OPTION_NAME = 279,
TOKEN_IP_ADDRESS = 280
}; };
}; };
@ -553,6 +555,10 @@ namespace isc { namespace eval {
symbol_type symbol_type
make_OPTION_NAME (const std::string& v, const location_type& l); make_OPTION_NAME (const std::string& v, const location_type& l);
static inline
symbol_type
make_IP_ADDRESS (const std::string& v, const location_type& l);
/// Build a parser object. /// Build a parser object.
EvalParser (EvalContext& ctx_yyarg); EvalParser (EvalContext& ctx_yyarg);
@ -758,12 +764,12 @@ namespace isc { namespace eval {
enum enum
{ {
yyeof_ = 0, yyeof_ = 0,
yylast_ = 70, ///< Last index in yytable_. yylast_ = 69, ///< Last index in yytable_.
yynnts_ = 8, ///< Number of nonterminal symbols. yynnts_ = 8, ///< Number of nonterminal symbols.
yyfinal_ = 18, ///< Termination state number. yyfinal_ = 19, ///< Termination state number.
yyterror_ = 1, yyterror_ = 1,
yyerrcode_ = 256, yyerrcode_ = 256,
yyntokens_ = 25 ///< Number of tokens. yyntokens_ = 26 ///< Number of tokens.
}; };
@ -807,9 +813,10 @@ namespace isc { namespace eval {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25
}; };
const unsigned int user_token_number_max_ = 279; const unsigned int user_token_number_max_ = 280;
const token_number_type undef_token_ = 2; const token_number_type undef_token_ = 2;
if (static_cast<int>(t) <= yyeof_) if (static_cast<int>(t) <= yyeof_)
@ -842,7 +849,7 @@ namespace isc { namespace eval {
{ {
switch (other.type_get ()) switch (other.type_get ())
{ {
case 30: // option_repr_type case 31: // option_repr_type
value.copy< TokenOption::RepresentationType > (other.value); value.copy< TokenOption::RepresentationType > (other.value);
break; break;
@ -850,10 +857,11 @@ namespace isc { namespace eval {
case 22: // "integer" case 22: // "integer"
case 23: // "constant hexstring" case 23: // "constant hexstring"
case 24: // "option name" case 24: // "option name"
case 25: // "ip address"
value.copy< std::string > (other.value); value.copy< std::string > (other.value);
break; break;
case 29: // option_code case 30: // option_code
value.copy< uint16_t > (other.value); value.copy< uint16_t > (other.value);
break; break;
@ -874,7 +882,7 @@ namespace isc { namespace eval {
(void) v; (void) v;
switch (this->type_get ()) switch (this->type_get ())
{ {
case 30: // option_repr_type case 31: // option_repr_type
value.copy< TokenOption::RepresentationType > (v); value.copy< TokenOption::RepresentationType > (v);
break; break;
@ -882,10 +890,11 @@ namespace isc { namespace eval {
case 22: // "integer" case 22: // "integer"
case 23: // "constant hexstring" case 23: // "constant hexstring"
case 24: // "option name" case 24: // "option name"
case 25: // "ip address"
value.copy< std::string > (v); value.copy< std::string > (v);
break; break;
case 29: // option_code case 30: // option_code
value.copy< uint16_t > (v); value.copy< uint16_t > (v);
break; break;
@ -951,7 +960,7 @@ namespace isc { namespace eval {
// Type destructor. // Type destructor.
switch (yytype) switch (yytype)
{ {
case 30: // option_repr_type case 31: // option_repr_type
value.template destroy< TokenOption::RepresentationType > (); value.template destroy< TokenOption::RepresentationType > ();
break; break;
@ -959,10 +968,11 @@ namespace isc { namespace eval {
case 22: // "integer" case 22: // "integer"
case 23: // "constant hexstring" case 23: // "constant hexstring"
case 24: // "option name" case 24: // "option name"
case 25: // "ip address"
value.template destroy< std::string > (); value.template destroy< std::string > ();
break; break;
case 29: // option_code case 30: // option_code
value.template destroy< uint16_t > (); value.template destroy< uint16_t > ();
break; break;
@ -989,7 +999,7 @@ namespace isc { namespace eval {
super_type::move(s); super_type::move(s);
switch (this->type_get ()) switch (this->type_get ())
{ {
case 30: // option_repr_type case 31: // option_repr_type
value.move< TokenOption::RepresentationType > (s.value); value.move< TokenOption::RepresentationType > (s.value);
break; break;
@ -997,10 +1007,11 @@ namespace isc { namespace eval {
case 22: // "integer" case 22: // "integer"
case 23: // "constant hexstring" case 23: // "constant hexstring"
case 24: // "option name" case 24: // "option name"
case 25: // "ip address"
value.move< std::string > (s.value); value.move< std::string > (s.value);
break; break;
case 29: // option_code case 30: // option_code
value.move< uint16_t > (s.value); value.move< uint16_t > (s.value);
break; break;
@ -1061,7 +1072,7 @@ namespace isc { namespace eval {
{ {
0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
275, 276, 277, 278, 279 275, 276, 277, 278, 279, 280
}; };
return static_cast<token_type> (yytoken_number_[type]); return static_cast<token_type> (yytoken_number_[type]);
} }
@ -1204,10 +1215,16 @@ namespace isc { namespace eval {
return symbol_type (token::TOKEN_OPTION_NAME, v, l); return symbol_type (token::TOKEN_OPTION_NAME, v, l);
} }
EvalParser::symbol_type
EvalParser::make_IP_ADDRESS (const std::string& v, const location_type& l)
{
return symbol_type (token::TOKEN_IP_ADDRESS, v, l);
}
#line 13 "parser.yy" // lalr1.cc:377
#line 13 "parser.yy" // lalr1.cc:392
} } // isc::eval } } // isc::eval
#line 1211 "parser.h" // lalr1.cc:377 #line 1228 "parser.h" // lalr1.cc:392

View File

@ -61,6 +61,7 @@ using namespace isc::eval;
%token <std::string> INTEGER "integer" %token <std::string> INTEGER "integer"
%token <std::string> HEXSTRING "constant hexstring" %token <std::string> HEXSTRING "constant hexstring"
%token <std::string> OPTION_NAME "option name" %token <std::string> OPTION_NAME "option name"
%token <std::string> IP_ADDRESS "ip address"
%type <uint16_t> option_code %type <uint16_t> option_code
%type <TokenOption::RepresentationType> option_repr_type %type <TokenOption::RepresentationType> option_repr_type
@ -139,6 +140,11 @@ string_expr : STRING
TokenPtr hex(new TokenHexString($1)); TokenPtr hex(new TokenHexString($1));
ctx.expression.push_back(hex); ctx.expression.push_back(hex);
} }
| IP_ADDRESS
{
TokenPtr ip(new TokenIpAddress($1));
ctx.expression.push_back(ip);
}
| OPTION "[" option_code "]" "." option_repr_type | OPTION "[" option_code "]" "." option_repr_type
{ {
TokenPtr opt(new TokenOption($3, $6)); TokenPtr opt(new TokenOption($3, $6));

View File

@ -50,9 +50,9 @@
# endif # endif
# endif # endif
#line 13 "parser.yy" // location.cc:296 #line 13 "parser.yy" // location.cc:337
namespace isc { namespace eval { namespace isc { namespace eval {
#line 56 "position.hh" // location.cc:296 #line 56 "position.hh" // location.cc:337
/// Abstract a position. /// Abstract a position.
class position class position
{ {
@ -174,7 +174,7 @@ namespace isc { namespace eval {
return ostr << pos.line << '.' << pos.column; return ostr << pos.line << '.' << pos.column;
} }
#line 13 "parser.yy" // location.cc:296 #line 13 "parser.yy" // location.cc:337
} } // isc::eval } } // isc::eval
#line 180 "position.hh" // location.cc:296 #line 180 "position.hh" // location.cc:337
#endif // !YY_YY_POSITION_HH_INCLUDED #endif // !YY_YY_POSITION_HH_INCLUDED

View File

@ -40,9 +40,9 @@
# include <vector> # include <vector>
#line 13 "parser.yy" // stack.hh:132 #line 13 "parser.yy" // stack.hh:151
namespace isc { namespace eval { namespace isc { namespace eval {
#line 46 "stack.hh" // stack.hh:132 #line 46 "stack.hh" // stack.hh:151
template <class T, class S = std::vector<T> > template <class T, class S = std::vector<T> >
class stack class stack
{ {
@ -150,8 +150,8 @@ namespace isc { namespace eval {
unsigned int range_; unsigned int range_;
}; };
#line 13 "parser.yy" // stack.hh:132 #line 13 "parser.yy" // stack.hh:151
} } // isc::eval } } // isc::eval
#line 156 "stack.hh" // stack.hh:132 #line 156 "stack.hh" // stack.hh:151
#endif // !YY_YY_STACK_HH_INCLUDED #endif // !YY_YY_STACK_HH_INCLUDED

View File

@ -10,12 +10,14 @@
#include <eval/token.h> #include <eval/token.h>
#include <dhcp/option.h> #include <dhcp/option.h>
#include <dhcp/pkt4.h> #include <dhcp/pkt4.h>
#include <asiolink/io_address.h>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h> #include <gtest/gtest.h>
using namespace std; using namespace std;
using namespace isc::asiolink;
using namespace isc::dhcp; using namespace isc::dhcp;
namespace { namespace {
@ -63,6 +65,29 @@ public:
EXPECT_EQ(expected, values.top()); EXPECT_EQ(expected, values.top());
} }
/// @brief checks if the given token is an IP address with the expected value
void checkTokenIpAddress(const TokenPtr& token,
const std::string& expected) {
ASSERT_TRUE(token);
boost::shared_ptr<TokenIpAddress> ipaddr =
boost::dynamic_pointer_cast<TokenIpAddress>(token);
ASSERT_TRUE(ipaddr);
Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, 12345));
ValueStack values;
EXPECT_NO_THROW(token->evaluate(*pkt4, values));
ASSERT_EQ(1, values.size());
string value = values.top();
boost::scoped_ptr<IOAddress> exp_ip;
ASSERT_NO_THROW(exp_ip.reset(new IOAddress(expected)));
vector<uint8_t> exp_addr = exp_ip->toBytes();
ASSERT_EQ(exp_addr.size(), value.size());
EXPECT_EQ(0, memcmp(&exp_addr[0], &value[0], value.size()));
}
/// @brief checks if the given token is an equal operator /// @brief checks if the given token is an equal operator
void checkTokenEq(const TokenPtr& token) { void checkTokenEq(const TokenPtr& token) {
ASSERT_TRUE(token); ASSERT_TRUE(token);
@ -215,6 +240,77 @@ TEST_F(EvalContextTest, oddHexstring) {
checkTokenHexString(tmp, "\a"); checkTokenHexString(tmp, "\a");
} }
// Test the parsing of an IPv4 address
TEST_F(EvalContextTest, ipaddress4) {
EvalContext eval(Option::V6);
EXPECT_NO_THROW(parsed_ = eval.parseString("10.0.0.1 == 'foo'"));
EXPECT_TRUE(parsed_);
ASSERT_EQ(3, eval.expression.size());
TokenPtr tmp = eval.expression.at(0);
checkTokenIpAddress(tmp, "10.0.0.1");
}
// Test the parsing of an IPv6 address
TEST_F(EvalContextTest, ipaddress6) {
EvalContext eval(Option::V6);
EXPECT_NO_THROW(parsed_ = eval.parseString("2001:db8::1 == 'foo'"));
EXPECT_TRUE(parsed_);
ASSERT_EQ(3, eval.expression.size());
TokenPtr tmp = eval.expression.at(0);
checkTokenIpAddress(tmp, "2001:db8::1");
}
// Test the parsing of an IPv4 compatible IPv6 address
TEST_F(EvalContextTest, ipaddress46) {
EvalContext eval(Option::V6);
EXPECT_NO_THROW(parsed_ = eval.parseString("::10.0.0.1 == 'foo'"));
EXPECT_TRUE(parsed_);
ASSERT_EQ(3, eval.expression.size());
TokenPtr tmp = eval.expression.at(0);
checkTokenIpAddress(tmp, "::10.0.0.1");
}
// Test the parsing of the unspecified IPv6 address
TEST_F(EvalContextTest, ipaddress6unspec) {
EvalContext eval(Option::V6);
EXPECT_NO_THROW(parsed_ = eval.parseString(":: == 'foo'"));
EXPECT_TRUE(parsed_);
ASSERT_EQ(3, eval.expression.size());
TokenPtr tmp = eval.expression.at(0);
checkTokenIpAddress(tmp, "::");
}
// Test the parsing of an IPv6 prefix
TEST_F(EvalContextTest, ipaddress6prefix) {
EvalContext eval(Option::V6);
EXPECT_NO_THROW(parsed_ = eval.parseString("2001:db8:: == 'foo'"));
EXPECT_TRUE(parsed_);
ASSERT_EQ(3, eval.expression.size());
TokenPtr tmp = eval.expression.at(0);
checkTokenIpAddress(tmp, "2001:db8::");
}
// Test the parsing of an equal expression // Test the parsing of an equal expression
TEST_F(EvalContextTest, equal) { TEST_F(EvalContextTest, equal) {
EvalContext eval(Option::V4); EvalContext eval(Option::V4);
@ -486,6 +582,7 @@ TEST_F(EvalContextTest, scanErrors) {
checkError("'\''", "<string>:1.3: Invalid character: '"); checkError("'\''", "<string>:1.3: Invalid character: '");
checkError("'\n'", "<string>:1.1: Invalid character: '"); checkError("'\n'", "<string>:1.1: Invalid character: '");
checkError("0x123h", "<string>:1.6: Invalid character: h"); checkError("0x123h", "<string>:1.6: Invalid character: h");
checkError(":1", "<string>:1.1: Invalid character: :");
checkError("=", "<string>:1.1: Invalid character: ="); checkError("=", "<string>:1.1: Invalid character: =");
checkError("subtring", "<string>:1.1: Invalid character: s"); checkError("subtring", "<string>:1.1: Invalid character: s");
checkError("foo", "<string>:1.1: Invalid character: f"); checkError("foo", "<string>:1.1: Invalid character: f");
@ -500,6 +597,12 @@ TEST_F(EvalContextTest, scanParseErrors) {
checkError("0x", "<string>:1.1: syntax error, unexpected integer"); checkError("0x", "<string>:1.1: syntax error, unexpected integer");
checkError("0abc", checkError("0abc",
"<string>:1.1: syntax error, unexpected integer"); "<string>:1.1: syntax error, unexpected integer");
checkError("10.0.1", "<string>:1.1-2: syntax error, unexpected integer");
checkError("10.256.0.1",
"<string>:1.1-10: Failed to convert 10.256.0.1 to "
"an IP address.");
checkError(":::",
"<string>:1.1-3: Failed to convert ::: to an IP address.");
checkError("===", "<string>:1.1-2: syntax error, unexpected =="); checkError("===", "<string>:1.1-2: syntax error, unexpected ==");
checkError("option[-1].text", checkError("option[-1].text",
"<string>:1.8-9: Option code has invalid " "<string>:1.8-9: Option code has invalid "

View File

@ -283,6 +283,51 @@ TEST_F(TokenTest, hexstring6) {
EXPECT_EQ("", values_.top()); EXPECT_EQ("", values_.top());
} }
// This test checks that a TokenIpAddress, representing an IP address as
// a constant string, can be used in Pkt4/Pkt6 evaluation.
// (The actual packet is not used)
TEST_F(TokenTest, ipaddress) {
TokenPtr bad4;
TokenPtr bad6;
TokenPtr ip4;
TokenPtr ip6;
// Bad IP addresses
ASSERT_NO_THROW(bad4.reset(new TokenIpAddress("10.0.0.0.1")));
ASSERT_NO_THROW(bad6.reset(new TokenIpAddress(":::")));
// IP addresses
ASSERT_NO_THROW(ip4.reset(new TokenIpAddress("10.0.0.1")));
ASSERT_NO_THROW(ip6.reset(new TokenIpAddress("2001:db8::1")));
// Make sure that tokens can be evaluated without exceptions.
ASSERT_NO_THROW(ip4->evaluate(*pkt4_, values_));
ASSERT_NO_THROW(ip6->evaluate(*pkt6_, values_));
ASSERT_NO_THROW(bad4->evaluate(*pkt4_, values_));
ASSERT_NO_THROW(bad6->evaluate(*pkt6_, values_));
// Check that the evaluation put its value on the values stack.
ASSERT_EQ(4, values_.size());
// Check bad addresses (they pushed '' on the value stack)
EXPECT_EQ(0, values_.top().size());
values_.pop();
EXPECT_EQ(0, values_.top().size());
values_.pop();
// Check IPv6 address
uint8_t expected6[] = { 0x20, 1, 0xd, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1 };
EXPECT_EQ(16, values_.top().size());
EXPECT_EQ(0, memcmp(expected6, &values_.top()[0], 16));
values_.pop();
// Check IPv4 address
uint8_t expected4[] = { 10, 0, 0, 1 };
EXPECT_EQ(4, values_.top().size());
EXPECT_EQ(0, memcmp(expected4, &values_.top()[0], 4));
}
// This test checks if a token representing an option value is able to extract // This test checks if a token representing an option value is able to extract
// the option from an IPv4 packet and properly store the option's value. // the option from an IPv4 packet and properly store the option's value.
TEST_F(TokenTest, optionString4) { TEST_F(TokenTest, optionString4) {

View File

@ -7,6 +7,7 @@
#include <eval/token.h> #include <eval/token.h>
#include <eval/eval_log.h> #include <eval/eval_log.h>
#include <util/encode/hex.h> #include <util/encode/hex.h>
#include <asiolink/io_address.h>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <cstring> #include <cstring>
#include <string> #include <string>
@ -54,6 +55,27 @@ TokenHexString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
values.push(value_); values.push(value_);
} }
TokenIpAddress::TokenIpAddress(const string& addr) : value_("") {
// Transform IP address into binary format
vector<uint8_t> binary;
try {
asiolink::IOAddress ip(addr);
binary = ip.toBytes();
} catch (...) {
return;
}
// Convert to a string (note that binary.size() is 4 or 16, so not 0)
value_.resize(binary.size());
memmove(&value_[0], &binary[0], binary.size());
}
void
TokenIpAddress::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
// Literals only push, nothing to pop
values.push(value_);
}
OptionPtr OptionPtr
TokenOption::getOption(const Pkt& pkt) { TokenOption::getOption(const Pkt& pkt) {
return (pkt.getOption(option_code_)); return (pkt.getOption(option_code_));

View File

@ -155,6 +155,29 @@ protected:
std::string value_; ///< Constant value std::string value_; ///< Constant value
}; };
/// @brief Token representing an IP address as a constant string
///
/// This token holds the value of an IP address as a constant string,
/// for instance 10.0.0.1 is 0x10000001
class TokenIpAddress : public Token {
public:
/// Value is set during token construction.
///
/// @param addr IP address to be represented as a constant string
TokenIpAddress(const std::string& addr);
/// @brief Token evaluation (puts value of the constant string on
/// the stack after decoding)
///
/// @param pkt (ignored)
/// @param values (represented IP address will be pushed here)
void evaluate(const Pkt& pkt, ValueStack& values);
protected:
///< Constant value (empty string if the IP address cannot be converted)
std::string value_;
};
/// @brief Token that represents a value of an option /// @brief Token that represents a value of an option
/// ///
/// This represents a reference to a given option, e.g. in the expression /// This represents a reference to a given option, e.g. in the expression