2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-31 14:05:33 +00:00

[master] Finish merge of trac4268a (DHCPv4 fields)

This commit is contained in:
Francis Dupont
2016-04-27 13:32:59 +02:00
11 changed files with 1277 additions and 608 deletions

View File

@@ -1,3 +1,8 @@
1107. [func] fdupont
Added support for extracting constant length fields from a DHCPv4
packet.
(Trac #4268, git xxx)
1106. [func] sar 1106. [func] sar
Added support for accessing DHCPv6 packet fields message type Added support for accessing DHCPv6 packet fields message type
and transaction id in a classification expression. and transaction id in a classification expression.

View File

@@ -152,56 +152,145 @@
<thead> <thead>
<row> <row>
<entry>Name</entry> <entry>Name</entry>
<entry>Example</entry> <entry>Example expression</entry>
<entry>Example value</entry>
<entry>Description</entry> <entry>Description</entry>
</row> </row>
</thead> </thead>
<tbody> <tbody>
<row><entry>String</entry><entry>'example'</entry><entry>A string</entry></row> <row>
<row><entry>Hex String</entry><entry>0XABCD</entry><entry>A hexadecimal string</entry></row> <entry>String literal</entry>
<row><entry>IP Address</entry><entry>10.0.0.1</entry><entry>An IP address</entry></row> <entry>'example'</entry>
<row><entry>Integer</entry><entry>123</entry><entry>An integer value</entry></row> <entry>'example'</entry>
<entry>A string</entry>
</row>
<row>
<entry>Hexadecimal string literal</entry>
<entry>0x5a7d</entry>
<entry>'Z}'</entry>
<entry>A hexadecimal string</entry>
</row>
<row>
<entry>IP address literal</entry>
<entry>10.0.0.1</entry>
<entry>0x0a000001</entry>
<entry>An IP address</entry>
</row>
<row>
<entry>Integer literal</entry>
<entry>123</entry>
<entry>'123'</entry>
<entry>An integer value</entry>
</row>
<row></row>
<row>
<entry>Binary content of the option</entry>
<entry>option[123].hex</entry>
<entry>'(content of the option)'</entry>
<entry>The value of the option with given code from the
packet as hex</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[123].text</entry>
<entry>'foobar'</entry>
<entry>The value of the option with given code from the
packet as text</entry>
</row>
--> -->
<row><entry>Option Hex</entry><entry>option[code].hex</entry><entry>The value of the option with code "code" from the packet as hex</entry></row> <row>
<row><entry>Option Exist</entry><entry>option[code].exist</entry><entry>If the option with code "code" is present in the packet "true" else "false"</entry></row> <entry>Option existence</entry>
<row><entry>DHCPv4 Relay Agent <entry>option[123].exist</entry>
sub-option</entry><entry>relay4[code].hex</entry><entry>The value of <entry>'true'</entry>
sub-option with code "code" from the DHCPv4 Relay Agent Information option <entry>If the option with given code is present in the
(option 82)</entry></row> packet "true" else "false"</entry>
<row> </row>
<row>
<entry>DHCPv4 relay agent sub-option</entry>
<entry>relay4[123].hex</entry>
<entry>'(content of the RAI sub-option)'</entry>
<entry>The value of sub-option with given code from the
DHCPv4 Relay Agent Information option (option 82)</entry>
</row>
<row>
<entry>DHCPv6 Relay Options</entry> <entry>DHCPv6 Relay Options</entry>
<entry>relay6[nest].option[code].hex</entry> <entry>relay6[nest].option[code].hex</entry>
<!-- <entry>Value of the option</entry> --> <!-- <entry>Value of the option</entry> -->
<entry>The value of the option with code "code" from the relay encapsulation "nest"</entry> <entry>The value of the option with code "code" from the
</row> relay encapsulation "nest"</entry>
<row> </row>
<row>
<entry>DHCPv6 Relay Peer Address</entry> <entry>DHCPv6 Relay Peer Address</entry>
<entry>relay6[nest].peeraddr</entry> <entry>relay6[nest].peeraddr</entry>
<!-- <entry>2001:DB8::1</entry> -->n <!-- <entry>2001:DB8::1</entry> -->n
<entry>The value of the peer address field from the relay encapsulation "nest"</entry> <entry>The value of the peer address field from the
</row> relay encapsulation "nest"</entry>
<row> </row>
<row>
<entry>DHCPv6 Relay Link Address</entry> <entry>DHCPv6 Relay Link Address</entry>
<entry>relay6[nest].linkaddr</entry> <entry>relay6[nest].linkaddr</entry>
<!-- <entry>2001:DB8::1</entry> -->n <!-- <entry>2001:DB8::1</entry> -->n
<entry>The value of the link address field from the relay encapsulation "nest"</entry> <entry>The value of the link address field from the
</row> relay encapsulation "nest"</entry>
<row> </row>
<row>
<entry>Hardware address in DHCPv4 packet</entry>
<entry>pkt4.mac</entry>
<entry>0x010203040506</entry>
<entry>The value of the chaddr field of the DHCPv4 packet, hlen (0 to 16) bytes</entry>
</row>
<row>
<entry>Hardware length in DHCPv4 packet</entry>
<entry>pkt4.hlen</entry>
<entry>0x00000006</entry>
<entry>The value of the hlen field of the DHCPv4 packet padded to 4 bytes</entry>
</row>
<row>
<entry>Hardware type in DHCPv4 packet</entry>
<entry>pkt4.htype</entry>
<entry>0x0000007b</entry>
<entry>The value of the htype field of the DHCPv4 packet padded to 4 bytes</entry>
</row>
<row>
<entry>ciaddr field in DHCPv4 packet</entry>
<entry>pkt4.ciaddr</entry>
<entry>192.0.2.1</entry>
<entry>The value of the ciaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)</entry>
</row>
<row>
<entry>giaddr field in DHCPv4 packet</entry>
<entry>pkt4.giaddr</entry>
<entry>192.0.2.1</entry>
<entry>The value of the giaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)</entry>
</row>
<row>
<entry>yiaddr field in DHCPv4 packet</entry>
<entry>pkt4.yiaddr</entry>
<entry>192.0.2.1</entry>
<entry>The value of the yiaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)</entry>
</row>
<row>
<entry>siaddr field in DHCPv4 packet</entry>
<entry>pkt4.siaddr</entry>
<entry>192.0.2.1</entry>
<entry>The value of the siaddr field of the DHCPv4 packet (IPv4 address, 4 bytes)</entry>
</row>
<row>
<entry>Message Type in DHCPv6 packet</entry> <entry>Message Type in DHCPv6 packet</entry>
<entry>pkt6.msgtype</entry> <entry>pkt6.msgtype</entry>
<!-- <entry>1</entry> <!-- <entry>1</entry> -->
--> <entry>The value of the message type field in the DHCPv6
<entry>The value of the message type field in the DHCPv6 packet.</entry> packet.</entry>
</row> </row>
<row> <row>
<entry>Transaction ID in DHCPv6 packet</entry> <entry>Transaction ID in DHCPv6 packet</entry>
<entry>pkt6.transid</entry> <entry>pkt6.transid</entry>
<!-- <entry>12345</entry> <!-- <entry>12345</entry> -->
--> <entry>The value of the transaction id in the DHCPv6
<entry>The value of the transaction id in the DHCPv6 packet.</entry> packet.</entry>
</row> </row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>
@@ -221,14 +310,14 @@ sub-option with code "code" from the DHCPv4 Relay Agent Information option
</para> </para>
<para> <para>
"option[code].hex" extracts the value of the option with the given code "option[code].hex" extracts the value of the option with the code "code"
from the incoming packet. If the packet doesn't contain the option, it from the incoming packet. If the packet doesn't contain the option, it
returns the empty string. The string is presented as a byte string of returns the empty string. The string is presented as a byte string of
the option payload without the type code or length fields. the option payload without the type code or length fields.
</para> </para>
<para> <para>
"option[code].exist" checks if an option with the given code is present "option[code].exist" checks if an option with the code "code" is present
in the incoming packet. It can be used with empty options. in the incoming packet. It can be used with empty options.
</para> </para>
@@ -261,6 +350,10 @@ sub-option with code "code" from the DHCPv4 Relay Agent Information option
"option", for instance "relay6[nest].option[code].exists" is supported. "option", for instance "relay6[nest].option[code].exists" is supported.
</para> </para>
<para>
Expressions starting with pkt4 can be used only in DHCPv4.
</para>
<para> <para>
"pkt6" refers to information from the client request. To access any "pkt6" refers to information from the client request. To access any
information from an intermediate relay use "relay6". "pkt6.msgtype" information from an intermediate relay use "relay6". "pkt6.msgtype"

File diff suppressed because it is too large Load Diff

View File

@@ -149,6 +149,14 @@ addr6 [0-9a-fA-F]*\:[0-9a-fA-F]*\:[0-9a-fA-F:.]*
"text" return isc::eval::EvalParser::make_TEXT(loc); "text" return isc::eval::EvalParser::make_TEXT(loc);
"hex" return isc::eval::EvalParser::make_HEX(loc); "hex" return isc::eval::EvalParser::make_HEX(loc);
"exists" return isc::eval::EvalParser::make_EXISTS(loc); "exists" return isc::eval::EvalParser::make_EXISTS(loc);
"pkt4" return isc::eval::EvalParser::make_PKT4(loc);
"mac" return isc::eval::EvalParser::make_CHADDR(loc);
"hlen" return isc::eval::EvalParser::make_HLEN(loc);
"htype" return isc::eval::EvalParser::make_HTYPE(loc);
"ciaddr" return isc::eval::EvalParser::make_CIADDR(loc);
"giaddr" return isc::eval::EvalParser::make_GIADDR(loc);
"yiaddr" return isc::eval::EvalParser::make_YIADDR(loc);
"siaddr" return isc::eval::EvalParser::make_SIADDR(loc);
"substring" return isc::eval::EvalParser::make_SUBSTRING(loc); "substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
"all" return isc::eval::EvalParser::make_ALL(loc); "all" return isc::eval::EvalParser::make_ALL(loc);
"concat" return isc::eval::EvalParser::make_CONCAT(loc); "concat" return isc::eval::EvalParser::make_CONCAT(loc);

View File

@@ -251,31 +251,35 @@ namespace isc { namespace eval {
{ {
switch (that.type_get ()) switch (that.type_get ())
{ {
case 37: // option_repr_type case 45: // option_repr_type
value.move< TokenOption::RepresentationType > (that.value); value.move< TokenOption::RepresentationType > (that.value);
break; break;
case 42: // pkt6_field case 46: // pkt4_field
value.move< TokenPkt4::FieldType > (that.value);
break;
case 51: // pkt6_field
value.move< TokenPkt6::FieldType > (that.value); value.move< TokenPkt6::FieldType > (that.value);
break; break;
case 40: // relay6_field case 49: // relay6_field
value.move< TokenRelay6Field::FieldType > (that.value); value.move< TokenRelay6Field::FieldType > (that.value);
break; break;
case 27: // "constant string" case 35: // "constant string"
case 28: // "integer" case 36: // "integer"
case 29: // "constant hexstring" case 37: // "constant hexstring"
case 30: // "option name" case 38: // "option name"
case 31: // "ip address" case 39: // "ip address"
value.move< std::string > (that.value); value.move< std::string > (that.value);
break; break;
case 36: // option_code case 44: // option_code
value.move< uint16_t > (that.value); value.move< uint16_t > (that.value);
break; break;
case 41: // nest_level case 50: // nest_level
value.move< uint8_t > (that.value); value.move< uint8_t > (that.value);
break; break;
@@ -294,31 +298,35 @@ namespace isc { namespace eval {
state = that.state; state = that.state;
switch (that.type_get ()) switch (that.type_get ())
{ {
case 37: // option_repr_type case 45: // option_repr_type
value.copy< TokenOption::RepresentationType > (that.value); value.copy< TokenOption::RepresentationType > (that.value);
break; break;
case 42: // pkt6_field case 46: // pkt4_field
value.copy< TokenPkt4::FieldType > (that.value);
break;
case 51: // pkt6_field
value.copy< TokenPkt6::FieldType > (that.value); value.copy< TokenPkt6::FieldType > (that.value);
break; break;
case 40: // relay6_field case 49: // relay6_field
value.copy< TokenRelay6Field::FieldType > (that.value); value.copy< TokenRelay6Field::FieldType > (that.value);
break; break;
case 27: // "constant string" case 35: // "constant string"
case 28: // "integer" case 36: // "integer"
case 29: // "constant hexstring" case 37: // "constant hexstring"
case 30: // "option name" case 38: // "option name"
case 31: // "ip address" case 39: // "ip address"
value.copy< std::string > (that.value); value.copy< std::string > (that.value);
break; break;
case 36: // option_code case 44: // option_code
value.copy< uint16_t > (that.value); value.copy< uint16_t > (that.value);
break; break;
case 41: // nest_level case 50: // nest_level
value.copy< uint8_t > (that.value); value.copy< uint8_t > (that.value);
break; break;
@@ -358,74 +366,81 @@ namespace isc { namespace eval {
<< yysym.location << ": "; << yysym.location << ": ";
switch (yytype) switch (yytype)
{ {
case 27: // "constant string" case 35: // "constant string"
#line 82 "parser.yy" // lalr1.cc:636 #line 91 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); } { yyoutput << yysym.value.template as< std::string > (); }
#line 366 "parser.cc" // lalr1.cc:636 #line 374 "parser.cc" // lalr1.cc:636
break; break;
case 28: // "integer" case 36: // "integer"
#line 82 "parser.yy" // lalr1.cc:636 #line 91 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); } { yyoutput << yysym.value.template as< std::string > (); }
#line 373 "parser.cc" // lalr1.cc:636 #line 381 "parser.cc" // lalr1.cc:636
break; break;
case 29: // "constant hexstring" case 37: // "constant hexstring"
#line 82 "parser.yy" // lalr1.cc:636 #line 91 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); } { yyoutput << yysym.value.template as< std::string > (); }
#line 380 "parser.cc" // lalr1.cc:636 #line 388 "parser.cc" // lalr1.cc:636
break; break;
case 30: // "option name" case 38: // "option name"
#line 82 "parser.yy" // lalr1.cc:636 #line 91 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); } { yyoutput << yysym.value.template as< std::string > (); }
#line 387 "parser.cc" // lalr1.cc:636 #line 395 "parser.cc" // lalr1.cc:636
break; break;
case 31: // "ip address" case 39: // "ip address"
#line 82 "parser.yy" // lalr1.cc:636 #line 91 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); } { yyoutput << yysym.value.template as< std::string > (); }
#line 394 "parser.cc" // lalr1.cc:636 #line 402 "parser.cc" // lalr1.cc:636
break; break;
case 36: // option_code case 44: // option_code
#line 82 "parser.yy" // lalr1.cc:636 #line 91 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< uint16_t > (); } { yyoutput << yysym.value.template as< uint16_t > (); }
#line 401 "parser.cc" // lalr1.cc:636 #line 409 "parser.cc" // lalr1.cc:636
break; break;
case 37: // option_repr_type case 45: // option_repr_type
#line 82 "parser.yy" // lalr1.cc:636 #line 91 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< TokenOption::RepresentationType > (); } { yyoutput << yysym.value.template as< TokenOption::RepresentationType > (); }
#line 408 "parser.cc" // lalr1.cc:636 #line 416 "parser.cc" // lalr1.cc:636
break; break;
case 40: // relay6_field case 46: // pkt4_field
#line 82 "parser.yy" // lalr1.cc:636 #line 91 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< TokenPkt4::FieldType > (); }
#line 423 "parser.cc" // lalr1.cc:636
break;
case 49: // relay6_field
#line 91 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< TokenRelay6Field::FieldType > (); } { yyoutput << yysym.value.template as< TokenRelay6Field::FieldType > (); }
#line 415 "parser.cc" // lalr1.cc:636 #line 430 "parser.cc" // lalr1.cc:636
break; break;
case 41: // nest_level case 50: // nest_level
#line 82 "parser.yy" // lalr1.cc:636 #line 91 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< uint8_t > (); } { yyoutput << yysym.value.template as< uint8_t > (); }
#line 422 "parser.cc" // lalr1.cc:636 #line 437 "parser.cc" // lalr1.cc:636
break; break;
case 42: // pkt6_field case 51: // pkt6_field
#line 82 "parser.yy" // lalr1.cc:636 #line 91 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< TokenPkt6::FieldType > (); } { yyoutput << yysym.value.template as< TokenPkt6::FieldType > (); }
#line 429 "parser.cc" // lalr1.cc:636 #line 444 "parser.cc" // lalr1.cc:636
break; break;
@@ -625,31 +640,35 @@ namespace isc { namespace eval {
when using variants. */ when using variants. */
switch (yyr1_[yyn]) switch (yyr1_[yyn])
{ {
case 37: // option_repr_type case 45: // option_repr_type
yylhs.value.build< TokenOption::RepresentationType > (); yylhs.value.build< TokenOption::RepresentationType > ();
break; break;
case 42: // pkt6_field case 46: // pkt4_field
yylhs.value.build< TokenPkt4::FieldType > ();
break;
case 51: // pkt6_field
yylhs.value.build< TokenPkt6::FieldType > (); yylhs.value.build< TokenPkt6::FieldType > ();
break; break;
case 40: // relay6_field case 49: // relay6_field
yylhs.value.build< TokenRelay6Field::FieldType > (); yylhs.value.build< TokenRelay6Field::FieldType > ();
break; break;
case 27: // "constant string" case 35: // "constant string"
case 28: // "integer" case 36: // "integer"
case 29: // "constant hexstring" case 37: // "constant hexstring"
case 30: // "option name" case 38: // "option name"
case 31: // "ip address" case 39: // "ip address"
yylhs.value.build< std::string > (); yylhs.value.build< std::string > ();
break; break;
case 36: // option_code case 44: // option_code
yylhs.value.build< uint16_t > (); yylhs.value.build< uint16_t > ();
break; break;
case 41: // nest_level case 50: // nest_level
yylhs.value.build< uint8_t > (); yylhs.value.build< uint8_t > ();
break; break;
@@ -671,52 +690,52 @@ namespace isc { namespace eval {
switch (yyn) switch (yyn)
{ {
case 4: case 4:
#line 96 "parser.yy" // lalr1.cc:859 #line 105 "parser.yy" // lalr1.cc:859
{ {
TokenPtr neg(new TokenNot()); TokenPtr neg(new TokenNot());
ctx.expression.push_back(neg); ctx.expression.push_back(neg);
} }
#line 680 "parser.cc" // lalr1.cc:859 #line 699 "parser.cc" // lalr1.cc:859
break; break;
case 5: case 5:
#line 101 "parser.yy" // lalr1.cc:859 #line 110 "parser.yy" // lalr1.cc:859
{ {
TokenPtr neg(new TokenAnd()); TokenPtr neg(new TokenAnd());
ctx.expression.push_back(neg); ctx.expression.push_back(neg);
} }
#line 689 "parser.cc" // lalr1.cc:859 #line 708 "parser.cc" // lalr1.cc:859
break; break;
case 6: case 6:
#line 106 "parser.yy" // lalr1.cc:859 #line 115 "parser.yy" // lalr1.cc:859
{ {
TokenPtr neg(new TokenOr()); TokenPtr neg(new TokenOr());
ctx.expression.push_back(neg); ctx.expression.push_back(neg);
} }
#line 698 "parser.cc" // lalr1.cc:859 #line 717 "parser.cc" // lalr1.cc:859
break; break;
case 7: case 7:
#line 111 "parser.yy" // lalr1.cc:859 #line 120 "parser.yy" // lalr1.cc:859
{ {
TokenPtr eq(new TokenEqual()); TokenPtr eq(new TokenEqual());
ctx.expression.push_back(eq); ctx.expression.push_back(eq);
} }
#line 707 "parser.cc" // lalr1.cc:859 #line 726 "parser.cc" // lalr1.cc:859
break; break;
case 8: case 8:
#line 116 "parser.yy" // lalr1.cc:859 #line 125 "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 716 "parser.cc" // lalr1.cc:859 #line 735 "parser.cc" // lalr1.cc:859
break; break;
case 9: case 9:
#line 121 "parser.yy" // lalr1.cc:859 #line 130 "parser.yy" // lalr1.cc:859
{ {
switch (ctx.getUniverse()) { switch (ctx.getUniverse()) {
case Option::V4: case Option::V4:
@@ -736,11 +755,11 @@ 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 740 "parser.cc" // lalr1.cc:859 #line 759 "parser.cc" // lalr1.cc:859
break; break;
case 10: case 10:
#line 141 "parser.yy" // lalr1.cc:859 #line 150 "parser.yy" // lalr1.cc:859
{ {
switch (ctx.getUniverse()) { switch (ctx.getUniverse()) {
case Option::V6: case Option::V6:
@@ -754,47 +773,47 @@ namespace isc { namespace eval {
error(yystack_[10].location, "relay6 can only be used in DHCPv6."); error(yystack_[10].location, "relay6 can only be used in DHCPv6.");
} }
} }
#line 758 "parser.cc" // lalr1.cc:859 #line 777 "parser.cc" // lalr1.cc:859
break; break;
case 11: case 11:
#line 157 "parser.yy" // lalr1.cc:859 #line 166 "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 767 "parser.cc" // lalr1.cc:859 #line 786 "parser.cc" // lalr1.cc:859
break; break;
case 12: case 12:
#line 162 "parser.yy" // lalr1.cc:859 #line 171 "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 776 "parser.cc" // lalr1.cc:859 #line 795 "parser.cc" // lalr1.cc:859
break; break;
case 13: case 13:
#line 167 "parser.yy" // lalr1.cc:859 #line 176 "parser.yy" // lalr1.cc:859
{ {
TokenPtr ip(new TokenIpAddress(yystack_[0].value.as< std::string > ())); TokenPtr ip(new TokenIpAddress(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(ip); ctx.expression.push_back(ip);
} }
#line 785 "parser.cc" // lalr1.cc:859 #line 804 "parser.cc" // lalr1.cc:859
break; break;
case 14: case 14:
#line 172 "parser.yy" // lalr1.cc:859 #line 181 "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 794 "parser.cc" // lalr1.cc:859 #line 813 "parser.cc" // lalr1.cc:859
break; break;
case 15: case 15:
#line 177 "parser.yy" // lalr1.cc:859 #line 186 "parser.yy" // lalr1.cc:859
{ {
switch (ctx.getUniverse()) { switch (ctx.getUniverse()) {
case Option::V4: case Option::V4:
@@ -814,11 +833,11 @@ 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 818 "parser.cc" // lalr1.cc:859 #line 837 "parser.cc" // lalr1.cc:859
break; break;
case 16: case 16:
#line 198 "parser.yy" // lalr1.cc:859 #line 207 "parser.yy" // lalr1.cc:859
{ {
switch (ctx.getUniverse()) { switch (ctx.getUniverse()) {
case Option::V6: case Option::V6:
@@ -832,11 +851,11 @@ namespace isc { namespace eval {
error(yystack_[10].location, "relay6 can only be used in DHCPv6."); error(yystack_[10].location, "relay6 can only be used in DHCPv6.");
} }
} }
#line 836 "parser.cc" // lalr1.cc:859 #line 855 "parser.cc" // lalr1.cc:859
break; break;
case 17: case 17:
#line 213 "parser.yy" // lalr1.cc:859 #line 222 "parser.yy" // lalr1.cc:859
{ {
switch (ctx.getUniverse()) { switch (ctx.getUniverse()) {
case Option::V6: case Option::V6:
@@ -850,129 +869,194 @@ namespace isc { namespace eval {
error(yystack_[5].location, "relay6 can only be used in DHCPv6."); error(yystack_[5].location, "relay6 can only be used in DHCPv6.");
} }
} }
#line 854 "parser.cc" // lalr1.cc:859 #line 873 "parser.cc" // lalr1.cc:859
break; break;
case 18: case 18:
#line 229 "parser.yy" // lalr1.cc:859 #line 237 "parser.yy" // lalr1.cc:859
{ {
TokenPtr sub(new TokenSubstring()); TokenPtr pkt4_field(new TokenPkt4(yystack_[0].value.as< TokenPkt4::FieldType > ()));
ctx.expression.push_back(sub); ctx.expression.push_back(pkt4_field);
} }
#line 863 "parser.cc" // lalr1.cc:859 #line 882 "parser.cc" // lalr1.cc:859
break; break;
case 19: case 19:
#line 234 "parser.yy" // lalr1.cc:859 #line 242 "parser.yy" // lalr1.cc:859
{
TokenPtr conc(new TokenConcat());
ctx.expression.push_back(conc);
}
#line 872 "parser.cc" // lalr1.cc:859
break;
case 20:
#line 239 "parser.yy" // lalr1.cc:859
{ {
TokenPtr pkt6_field(new TokenPkt6(yystack_[0].value.as< TokenPkt6::FieldType > ())); TokenPtr pkt6_field(new TokenPkt6(yystack_[0].value.as< TokenPkt6::FieldType > ()));
ctx.expression.push_back(pkt6_field); ctx.expression.push_back(pkt6_field);
} }
#line 881 "parser.cc" // lalr1.cc:859 #line 891 "parser.cc" // lalr1.cc:859
break;
case 20:
#line 247 "parser.yy" // lalr1.cc:859
{
TokenPtr sub(new TokenSubstring());
ctx.expression.push_back(sub);
}
#line 900 "parser.cc" // lalr1.cc:859
break; break;
case 21: case 21:
#line 246 "parser.yy" // lalr1.cc:859 #line 252 "parser.yy" // lalr1.cc:859
{ {
yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location); TokenPtr conc(new TokenConcat());
ctx.expression.push_back(conc);
} }
#line 889 "parser.cc" // lalr1.cc:859 #line 909 "parser.cc" // lalr1.cc:859
break; break;
case 22: case 22:
#line 250 "parser.yy" // lalr1.cc:859 #line 259 "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 897 "parser.cc" // lalr1.cc:859 #line 917 "parser.cc" // lalr1.cc:859
break; break;
case 23: case 23:
#line 256 "parser.yy" // lalr1.cc:859 #line 263 "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 905 "parser.cc" // lalr1.cc:859 #line 925 "parser.cc" // lalr1.cc:859
break; break;
case 24: case 24:
#line 260 "parser.yy" // lalr1.cc:859 #line 269 "parser.yy" // lalr1.cc:859
{ {
yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL; yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL;
} }
#line 913 "parser.cc" // lalr1.cc:859 #line 933 "parser.cc" // lalr1.cc:859
break; break;
case 25: case 25:
#line 266 "parser.yy" // lalr1.cc:859 #line 273 "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 922 "parser.cc" // lalr1.cc:859 #line 941 "parser.cc" // lalr1.cc:859
break; break;
case 26: case 26:
#line 273 "parser.yy" // lalr1.cc:859 #line 279 "parser.yy" // lalr1.cc:859
{
yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::CHADDR;
}
#line 949 "parser.cc" // lalr1.cc:859
break;
case 27:
#line 283 "parser.yy" // lalr1.cc:859
{
yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::HLEN;
}
#line 957 "parser.cc" // lalr1.cc:859
break;
case 28:
#line 287 "parser.yy" // lalr1.cc:859
{
yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::HTYPE;
}
#line 965 "parser.cc" // lalr1.cc:859
break;
case 29:
#line 291 "parser.yy" // lalr1.cc:859
{
yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::CIADDR;
}
#line 973 "parser.cc" // lalr1.cc:859
break;
case 30:
#line 295 "parser.yy" // lalr1.cc:859
{
yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::GIADDR;
}
#line 981 "parser.cc" // lalr1.cc:859
break;
case 31:
#line 299 "parser.yy" // lalr1.cc:859
{
yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::YIADDR;
}
#line 989 "parser.cc" // lalr1.cc:859
break;
case 32:
#line 303 "parser.yy" // lalr1.cc:859
{
yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::SIADDR;
}
#line 997 "parser.cc" // lalr1.cc:859
break;
case 33:
#line 309 "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 931 "parser.cc" // lalr1.cc:859 #line 1006 "parser.cc" // lalr1.cc:859
break; break;
case 27: case 34:
#line 278 "parser.yy" // lalr1.cc:859 #line 316 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str);
}
#line 1015 "parser.cc" // lalr1.cc:859
break;
case 35:
#line 321 "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 940 "parser.cc" // lalr1.cc:859 #line 1024 "parser.cc" // lalr1.cc:859
break; break;
case 28: case 36:
#line 284 "parser.yy" // lalr1.cc:859 #line 327 "parser.yy" // lalr1.cc:859
{ yylhs.value.as< TokenRelay6Field::FieldType > () = TokenRelay6Field::PEERADDR; } { yylhs.value.as< TokenRelay6Field::FieldType > () = TokenRelay6Field::PEERADDR; }
#line 946 "parser.cc" // lalr1.cc:859 #line 1030 "parser.cc" // lalr1.cc:859
break; break;
case 29: case 37:
#line 285 "parser.yy" // lalr1.cc:859 #line 328 "parser.yy" // lalr1.cc:859
{ yylhs.value.as< TokenRelay6Field::FieldType > () = TokenRelay6Field::LINKADDR; } { yylhs.value.as< TokenRelay6Field::FieldType > () = TokenRelay6Field::LINKADDR; }
#line 952 "parser.cc" // lalr1.cc:859 #line 1036 "parser.cc" // lalr1.cc:859
break; break;
case 30: case 38:
#line 289 "parser.yy" // lalr1.cc:859 #line 332 "parser.yy" // lalr1.cc:859
{ {
yylhs.value.as< uint8_t > () = ctx.convertNestLevelNumber(yystack_[0].value.as< std::string > (), yystack_[0].location); yylhs.value.as< uint8_t > () = ctx.convertNestLevelNumber(yystack_[0].value.as< std::string > (), yystack_[0].location);
} }
#line 960 "parser.cc" // lalr1.cc:859 #line 1044 "parser.cc" // lalr1.cc:859
break; break;
case 31: case 39:
#line 297 "parser.yy" // lalr1.cc:859 #line 340 "parser.yy" // lalr1.cc:859
{ yylhs.value.as< TokenPkt6::FieldType > () = TokenPkt6::MSGTYPE; } { yylhs.value.as< TokenPkt6::FieldType > () = TokenPkt6::MSGTYPE; }
#line 966 "parser.cc" // lalr1.cc:859 #line 1050 "parser.cc" // lalr1.cc:859
break; break;
case 32: case 40:
#line 298 "parser.yy" // lalr1.cc:859 #line 341 "parser.yy" // lalr1.cc:859
{ yylhs.value.as< TokenPkt6::FieldType > () = TokenPkt6::TRANSID; } { yylhs.value.as< TokenPkt6::FieldType > () = TokenPkt6::TRANSID; }
#line 972 "parser.cc" // lalr1.cc:859 #line 1056 "parser.cc" // lalr1.cc:859
break; break;
#line 976 "parser.cc" // lalr1.cc:859 #line 1060 "parser.cc" // lalr1.cc:859
default: default:
break; break;
} }
@@ -1227,117 +1311,124 @@ namespace isc { namespace eval {
} }
const signed char EvalParser::yypact_ninf_ = -54; const signed char EvalParser::yypact_ninf_ = -62;
const signed char EvalParser::yytable_ninf_ = -1; const signed char EvalParser::yytable_ninf_ = -1;
const signed char const signed char
EvalParser::yypact_[] = EvalParser::yypact_[] =
{ {
29, 29, 29, -12, -4, 7, 21, 30, 32, -54, 14, 14, 14, 6, 17, 18, 21, 41, 44, 48,
-54, -54, 13, 10, 46, 16, -54, -3, -3, 9, -62, -62, -62, 72, 20, 66, 29, -62, 12, 12,
52, 52, 42, -54, 29, 29, 52, -54, -54, -54, 16, 36, 45, 45, -24, -62, 14, 14, 45, -62,
40, 54, -54, 56, 43, 59, 60, 55, 58, -54, -62, -62, 60, 63, -62, 73, -62, -62, -62, -62,
-54, -54, -54, 72, -54, 66, 68, 69, -3, -3, -62, -62, -62, -62, 67, 69, 75, 61, 62, -62,
9, 61, 52, 25, 28, -1, 71, 73, 75, -54, -62, -62, -62, 84, -62, 77, 78, 79, 12, 12,
65, 87, -54, -54, -54, -54, -54, -54, 78, -54, 16, 64, 45, -3, 52, -1, 81, 82, 83, -62,
-54, -54, 77, 79, 80, -14, -54, -3, 33, 33, 71, 95, -62, -62, -62, -62, -62, -62, 88, -62,
6, -54, -54, 90, 82, 84, -54, 83, -3, 47, -62, -62, 87, 89, 90, -23, -62, 12, 49, 49,
85, -54, -54, 86, 33 9, -62, -62, 100, 92, 94, -62, 93, 12, 68,
96, -62, -62, 97, 49
}; };
const unsigned char const unsigned char
EvalParser::yydefact_[] = EvalParser::yydefact_[] =
{ {
0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
12, 13, 0, 2, 0, 0, 4, 0, 0, 0, 11, 12, 13, 0, 2, 0, 0, 4, 0, 0,
0, 0, 0, 1, 0, 0, 0, 3, 21, 22, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3,
0, 0, 30, 0, 0, 0, 0, 0, 0, 31, 22, 23, 0, 0, 38, 0, 26, 27, 28, 29,
32, 20, 5, 6, 7, 0, 0, 0, 0, 0, 30, 31, 32, 18, 0, 0, 0, 0, 0, 39,
0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 40, 19, 5, 6, 7, 0, 0, 0, 0, 0,
0, 0, 23, 24, 8, 14, 9, 15, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33,
29, 17, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 24, 25, 8, 14, 9, 15, 0, 36,
0, 27, 26, 0, 0, 0, 18, 0, 0, 0, 37, 17, 0, 0, 0, 0, 21, 0, 0, 0,
0, 35, 34, 0, 0, 0, 20, 0, 0, 0,
0, 10, 16, 0, 0 0, 10, 16, 0, 0
}; };
const signed char const signed char
EvalParser::yypgoto_[] = EvalParser::yypgoto_[] =
{ {
-54, -54, 4, -17, -18, -53, -54, -54, -54, 51, -62, -62, 3, -21, -19, -61, -62, -62, -62, -62,
-54 50, -62
}; };
const signed char const signed char
EvalParser::yydefgoto_[] = EvalParser::yydefgoto_[] =
{ {
-1, 12, 13, 14, 30, 65, 60, 83, 71, 33, -1, 13, 14, 15, 32, 75, 43, 70, 93, 81,
41 35, 51
}; };
const unsigned char const unsigned char
EvalParser::yytable_[] = EvalParser::yytable_[] =
{ {
31, 67, 17, 37, 38, 15, 16, 81, 68, 44, 33, 47, 48, 77, 16, 17, 91, 54, 78, 49,
18, 69, 70, 23, 82, 85, 24, 25, 69, 70, 50, 79, 80, 92, 72, 73, 74, 1, 95, 2,
27, 19, 24, 25, 20, 28, 67, 29, 42, 43, 18, 79, 80, 3, 4, 5, 26, 27, 77, 52,
56, 57, 1, 21, 2, 61, 92, 32, 3, 4, 53, 19, 20, 29, 6, 26, 27, 21, 102, 66,
5, 92, 62, 63, 64, 62, 63, 66, 22, 6, 67, 71, 7, 102, 22, 8, 9, 23, 30, 10,
62, 63, 7, 8, 26, 45, 9, 48, 10, 84, 31, 11, 34, 12, 44, 45, 46, 36, 37, 38,
11, 34, 35, 36, 62, 63, 91, 39, 40, 46, 39, 40, 41, 42, 24, 6, 72, 73, 94, 72,
90, 47, 6, 49, 50, 7, 8, 51, 24, 9, 73, 76, 25, 7, 28, 55, 8, 9, 56, 100,
52, 10, 53, 11, 54, 55, 72, 75, 73, 59, 10, 58, 11, 59, 12, 72, 73, 101, 57, 60,
74, 76, 77, 78, 86, 79, 80, 87, 88, 89, 26, 61, 62, 63, 64, 65, 82, 83, 84, 86,
93, 58, 94 69, 85, 87, 88, 96, 89, 90, 97, 98, 99,
68, 103, 0, 104
}; };
const unsigned char const signed char
EvalParser::yycheck_[] = EvalParser::yycheck_[] =
{ {
18, 54, 14, 20, 21, 1, 2, 21, 9, 26, 19, 22, 23, 64, 1, 2, 29, 28, 9, 33,
14, 12, 13, 0, 28, 9, 6, 7, 12, 13, 34, 12, 13, 36, 17, 18, 19, 3, 9, 5,
4, 14, 6, 7, 3, 28, 79, 30, 24, 25, 14, 12, 13, 9, 10, 11, 6, 7, 89, 26,
48, 49, 3, 3, 5, 52, 89, 28, 9, 10, 27, 14, 14, 4, 20, 6, 7, 16, 99, 58,
11, 94, 17, 18, 19, 17, 18, 19, 16, 20, 59, 62, 28, 104, 3, 31, 32, 3, 36, 35,
17, 18, 23, 24, 8, 15, 27, 14, 29, 77, 38, 37, 36, 39, 9, 10, 11, 21, 22, 23,
31, 9, 10, 11, 17, 18, 19, 25, 26, 15, 24, 25, 26, 27, 16, 20, 17, 18, 87, 17,
88, 15, 20, 14, 14, 23, 24, 22, 6, 27, 18, 19, 0, 28, 8, 15, 31, 32, 15, 98,
22, 29, 16, 31, 16, 16, 15, 22, 15, 28, 35, 14, 37, 14, 39, 17, 18, 19, 15, 14,
15, 4, 14, 16, 4, 16, 16, 15, 14, 16, 6, 30, 30, 16, 16, 16, 15, 15, 15, 4,
15, 50, 16 36, 30, 14, 16, 4, 16, 16, 15, 14, 16,
60, 15, -1, 16
}; };
const unsigned char const unsigned char
EvalParser::yystos_[] = EvalParser::yystos_[] =
{ {
0, 3, 5, 9, 10, 11, 20, 23, 24, 27, 0, 3, 5, 9, 10, 11, 20, 28, 31, 32,
29, 31, 33, 34, 35, 34, 34, 14, 14, 14, 35, 37, 39, 41, 42, 43, 42, 42, 14, 14,
3, 3, 16, 0, 6, 7, 8, 4, 28, 30, 14, 16, 3, 3, 16, 0, 6, 7, 8, 4,
36, 36, 28, 41, 9, 10, 11, 35, 35, 25, 36, 38, 44, 44, 36, 50, 21, 22, 23, 24,
26, 42, 34, 34, 35, 15, 15, 15, 14, 14, 25, 26, 27, 46, 9, 10, 11, 43, 43, 33,
14, 22, 22, 16, 16, 16, 36, 36, 41, 28, 34, 51, 42, 42, 43, 15, 15, 15, 14, 14,
38, 35, 17, 18, 19, 37, 19, 37, 9, 12, 14, 30, 30, 16, 16, 16, 44, 44, 50, 36,
13, 40, 15, 15, 15, 22, 4, 14, 16, 16, 47, 43, 17, 18, 19, 45, 19, 45, 9, 12,
16, 21, 28, 39, 36, 9, 4, 15, 14, 16, 13, 49, 15, 15, 15, 30, 4, 14, 16, 16,
36, 19, 37, 15, 16 16, 29, 36, 48, 44, 9, 4, 15, 14, 16,
44, 19, 45, 15, 16
}; };
const unsigned char const unsigned char
EvalParser::yyr1_[] = EvalParser::yyr1_[] =
{ {
0, 32, 33, 34, 34, 34, 34, 34, 34, 34, 0, 40, 41, 42, 42, 42, 42, 42, 42, 42,
34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 42, 43, 43, 43, 43, 43, 43, 43, 43, 43,
35, 36, 36, 37, 37, 38, 39, 39, 40, 40, 43, 43, 44, 44, 45, 45, 46, 46, 46, 46,
41, 42, 42 46, 46, 46, 47, 48, 48, 49, 49, 50, 51,
51
}; };
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,
11, 1, 1, 1, 6, 6, 11, 6, 8, 6, 11, 1, 1, 1, 6, 6, 11, 6, 3, 3,
3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 6, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1
}; };
@@ -1350,22 +1441,25 @@ namespace isc { namespace eval {
"\"end of file\"", "error", "$undefined", "\"(\"", "\")\"", "\"not\"", "\"end of file\"", "error", "$undefined", "\"(\"", "\")\"", "\"not\"",
"\"and\"", "\"or\"", "\"==\"", "\"option\"", "\"relay4\"", "\"relay6\"", "\"and\"", "\"or\"", "\"==\"", "\"option\"", "\"relay4\"", "\"relay6\"",
"\"peeraddr\"", "\"linkaddr\"", "\"[\"", "\"]\"", "\".\"", "\"text\"", "\"peeraddr\"", "\"linkaddr\"", "\"[\"", "\"]\"", "\".\"", "\"text\"",
"\"hex\"", "\"exists\"", "\"substring\"", "\"all\"", "\",\"", "\"hex\"", "\"exists\"", "\"pkt4\"", "\"mac\"", "\"hlen\"", "\"htype\"",
"\"concat\"", "\"pkt6\"", "\"msgtype\"", "\"transid\"", "\"ciaddr\"", "\"giaddr\"", "\"yiaddr\"", "\"siaddr\"", "\"substring\"",
"\"constant string\"", "\"integer\"", "\"constant hexstring\"", "\"all\"", "\",\"", "\"concat\"", "\"pkt6\"", "\"msgtype\"",
"\"option name\"", "\"ip address\"", "$accept", "expression", "\"transid\"", "\"constant string\"", "\"integer\"",
"bool_expr", "string_expr", "option_code", "option_repr_type", "\"constant hexstring\"", "\"option name\"", "\"ip address\"", "$accept",
"start_expr", "length_expr", "relay6_field", "nest_level", "pkt6_field", YY_NULLPTR "expression", "bool_expr", "string_expr", "option_code",
"option_repr_type", "pkt4_field", "start_expr", "length_expr",
"relay6_field", "nest_level", "pkt6_field", YY_NULLPTR
}; };
#if YYDEBUG #if YYDEBUG
const unsigned short int const unsigned short int
EvalParser::yyrline_[] = EvalParser::yyrline_[] =
{ {
0, 91, 91, 94, 95, 100, 105, 110, 115, 120, 0, 100, 100, 103, 104, 109, 114, 119, 124, 129,
140, 156, 161, 166, 171, 176, 197, 212, 228, 233, 149, 165, 170, 175, 180, 185, 206, 221, 236, 241,
238, 245, 249, 255, 259, 265, 272, 277, 284, 285, 246, 251, 258, 262, 268, 272, 278, 282, 286, 290,
288, 297, 298 294, 298, 302, 308, 315, 320, 327, 328, 331, 340,
341
}; };
// Print the state stack on the debug stream. // Print the state stack on the debug stream.
@@ -1400,8 +1494,8 @@ namespace isc { namespace eval {
#line 13 "parser.yy" // lalr1.cc:1167 #line 13 "parser.yy" // lalr1.cc:1167
} } // isc::eval } } // isc::eval
#line 1404 "parser.cc" // lalr1.cc:1167 #line 1498 "parser.cc" // lalr1.cc:1167
#line 301 "parser.yy" // lalr1.cc:1168 #line 344 "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
@@ -298,24 +298,27 @@ namespace isc { namespace eval {
// option_repr_type // option_repr_type
char dummy1[sizeof(TokenOption::RepresentationType)]; char dummy1[sizeof(TokenOption::RepresentationType)];
// pkt4_field
char dummy2[sizeof(TokenPkt4::FieldType)];
// pkt6_field // pkt6_field
char dummy2[sizeof(TokenPkt6::FieldType)]; char dummy3[sizeof(TokenPkt6::FieldType)];
// relay6_field // relay6_field
char dummy3[sizeof(TokenRelay6Field::FieldType)]; char dummy4[sizeof(TokenRelay6Field::FieldType)];
// "constant string" // "constant string"
// "integer" // "integer"
// "constant hexstring" // "constant hexstring"
// "option name" // "option name"
// "ip address" // "ip address"
char dummy4[sizeof(std::string)]; char dummy5[sizeof(std::string)];
// option_code // option_code
char dummy5[sizeof(uint16_t)]; char dummy6[sizeof(uint16_t)];
// nest_level // nest_level
char dummy6[sizeof(uint8_t)]; char dummy7[sizeof(uint8_t)];
}; };
/// Symbol semantic values. /// Symbol semantic values.
@@ -356,18 +359,26 @@ namespace isc { namespace eval {
TOKEN_TEXT = 272, TOKEN_TEXT = 272,
TOKEN_HEX = 273, TOKEN_HEX = 273,
TOKEN_EXISTS = 274, TOKEN_EXISTS = 274,
TOKEN_SUBSTRING = 275, TOKEN_PKT4 = 275,
TOKEN_ALL = 276, TOKEN_CHADDR = 276,
TOKEN_COMA = 277, TOKEN_HLEN = 277,
TOKEN_CONCAT = 278, TOKEN_HTYPE = 278,
TOKEN_PKT6 = 279, TOKEN_CIADDR = 279,
TOKEN_MSGTYPE = 280, TOKEN_GIADDR = 280,
TOKEN_TRANSID = 281, TOKEN_YIADDR = 281,
TOKEN_STRING = 282, TOKEN_SIADDR = 282,
TOKEN_INTEGER = 283, TOKEN_SUBSTRING = 283,
TOKEN_HEXSTRING = 284, TOKEN_ALL = 284,
TOKEN_OPTION_NAME = 285, TOKEN_COMA = 285,
TOKEN_IP_ADDRESS = 286 TOKEN_CONCAT = 286,
TOKEN_PKT6 = 287,
TOKEN_MSGTYPE = 288,
TOKEN_TRANSID = 289,
TOKEN_STRING = 290,
TOKEN_INTEGER = 291,
TOKEN_HEXSTRING = 292,
TOKEN_OPTION_NAME = 293,
TOKEN_IP_ADDRESS = 294
}; };
}; };
@@ -407,6 +418,8 @@ namespace isc { namespace eval {
basic_symbol (typename Base::kind_type t, const TokenOption::RepresentationType v, const location_type& l); basic_symbol (typename Base::kind_type t, const TokenOption::RepresentationType v, const location_type& l);
basic_symbol (typename Base::kind_type t, const TokenPkt4::FieldType v, const location_type& l);
basic_symbol (typename Base::kind_type t, const TokenPkt6::FieldType v, const location_type& l); basic_symbol (typename Base::kind_type t, const TokenPkt6::FieldType v, const location_type& l);
basic_symbol (typename Base::kind_type t, const TokenRelay6Field::FieldType v, const location_type& l); basic_symbol (typename Base::kind_type t, const TokenRelay6Field::FieldType v, const location_type& l);
@@ -556,6 +569,38 @@ namespace isc { namespace eval {
symbol_type symbol_type
make_EXISTS (const location_type& l); make_EXISTS (const location_type& l);
static inline
symbol_type
make_PKT4 (const location_type& l);
static inline
symbol_type
make_CHADDR (const location_type& l);
static inline
symbol_type
make_HLEN (const location_type& l);
static inline
symbol_type
make_HTYPE (const location_type& l);
static inline
symbol_type
make_CIADDR (const location_type& l);
static inline
symbol_type
make_GIADDR (const location_type& l);
static inline
symbol_type
make_YIADDR (const location_type& l);
static inline
symbol_type
make_SIADDR (const location_type& l);
static inline static inline
symbol_type symbol_type
make_SUBSTRING (const location_type& l); make_SUBSTRING (const location_type& l);
@@ -689,7 +734,7 @@ namespace isc { namespace eval {
// number is the opposite. If YYTABLE_NINF, syntax error. // number is the opposite. If YYTABLE_NINF, syntax error.
static const unsigned char yytable_[]; static const unsigned char yytable_[];
static const unsigned char yycheck_[]; static const signed char yycheck_[];
// YYSTOS[STATE-NUM] -- The (internal number of the) accessing // YYSTOS[STATE-NUM] -- The (internal number of the) accessing
// symbol of state STATE-NUM. // symbol of state STATE-NUM.
@@ -809,12 +854,12 @@ namespace isc { namespace eval {
enum enum
{ {
yyeof_ = 0, yyeof_ = 0,
yylast_ = 102, ///< Last index in yytable_. yylast_ = 113, ///< Last index in yytable_.
yynnts_ = 11, ///< Number of nonterminal symbols. yynnts_ = 12, ///< Number of nonterminal symbols.
yyfinal_ = 23, ///< Termination state number. yyfinal_ = 25, ///< Termination state number.
yyterror_ = 1, yyterror_ = 1,
yyerrcode_ = 256, yyerrcode_ = 256,
yyntokens_ = 32 ///< Number of tokens. yyntokens_ = 40 ///< Number of tokens.
}; };
@@ -859,9 +904,10 @@ namespace isc { namespace eval {
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, 26, 27, 28, 29, 30, 31 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39
}; };
const unsigned int user_token_number_max_ = 286; const unsigned int user_token_number_max_ = 294;
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_)
@@ -894,31 +940,35 @@ namespace isc { namespace eval {
{ {
switch (other.type_get ()) switch (other.type_get ())
{ {
case 37: // option_repr_type case 45: // option_repr_type
value.copy< TokenOption::RepresentationType > (other.value); value.copy< TokenOption::RepresentationType > (other.value);
break; break;
case 42: // pkt6_field case 46: // pkt4_field
value.copy< TokenPkt4::FieldType > (other.value);
break;
case 51: // pkt6_field
value.copy< TokenPkt6::FieldType > (other.value); value.copy< TokenPkt6::FieldType > (other.value);
break; break;
case 40: // relay6_field case 49: // relay6_field
value.copy< TokenRelay6Field::FieldType > (other.value); value.copy< TokenRelay6Field::FieldType > (other.value);
break; break;
case 27: // "constant string" case 35: // "constant string"
case 28: // "integer" case 36: // "integer"
case 29: // "constant hexstring" case 37: // "constant hexstring"
case 30: // "option name" case 38: // "option name"
case 31: // "ip address" case 39: // "ip address"
value.copy< std::string > (other.value); value.copy< std::string > (other.value);
break; break;
case 36: // option_code case 44: // option_code
value.copy< uint16_t > (other.value); value.copy< uint16_t > (other.value);
break; break;
case 41: // nest_level case 50: // nest_level
value.copy< uint8_t > (other.value); value.copy< uint8_t > (other.value);
break; break;
@@ -939,31 +989,35 @@ namespace isc { namespace eval {
(void) v; (void) v;
switch (this->type_get ()) switch (this->type_get ())
{ {
case 37: // option_repr_type case 45: // option_repr_type
value.copy< TokenOption::RepresentationType > (v); value.copy< TokenOption::RepresentationType > (v);
break; break;
case 42: // pkt6_field case 46: // pkt4_field
value.copy< TokenPkt4::FieldType > (v);
break;
case 51: // pkt6_field
value.copy< TokenPkt6::FieldType > (v); value.copy< TokenPkt6::FieldType > (v);
break; break;
case 40: // relay6_field case 49: // relay6_field
value.copy< TokenRelay6Field::FieldType > (v); value.copy< TokenRelay6Field::FieldType > (v);
break; break;
case 27: // "constant string" case 35: // "constant string"
case 28: // "integer" case 36: // "integer"
case 29: // "constant hexstring" case 37: // "constant hexstring"
case 30: // "option name" case 38: // "option name"
case 31: // "ip address" case 39: // "ip address"
value.copy< std::string > (v); value.copy< std::string > (v);
break; break;
case 36: // option_code case 44: // option_code
value.copy< uint16_t > (v); value.copy< uint16_t > (v);
break; break;
case 41: // nest_level case 50: // nest_level
value.copy< uint8_t > (v); value.copy< uint8_t > (v);
break; break;
@@ -989,6 +1043,13 @@ namespace isc { namespace eval {
, location (l) , location (l)
{} {}
template <typename Base>
EvalParser::basic_symbol<Base>::basic_symbol (typename Base::kind_type t, const TokenPkt4::FieldType v, const location_type& l)
: Base (t)
, value (v)
, location (l)
{}
template <typename Base> template <typename Base>
EvalParser::basic_symbol<Base>::basic_symbol (typename Base::kind_type t, const TokenPkt6::FieldType v, const location_type& l) EvalParser::basic_symbol<Base>::basic_symbol (typename Base::kind_type t, const TokenPkt6::FieldType v, const location_type& l)
: Base (t) : Base (t)
@@ -1050,31 +1111,35 @@ namespace isc { namespace eval {
// Type destructor. // Type destructor.
switch (yytype) switch (yytype)
{ {
case 37: // option_repr_type case 45: // option_repr_type
value.template destroy< TokenOption::RepresentationType > (); value.template destroy< TokenOption::RepresentationType > ();
break; break;
case 42: // pkt6_field case 46: // pkt4_field
value.template destroy< TokenPkt4::FieldType > ();
break;
case 51: // pkt6_field
value.template destroy< TokenPkt6::FieldType > (); value.template destroy< TokenPkt6::FieldType > ();
break; break;
case 40: // relay6_field case 49: // relay6_field
value.template destroy< TokenRelay6Field::FieldType > (); value.template destroy< TokenRelay6Field::FieldType > ();
break; break;
case 27: // "constant string" case 35: // "constant string"
case 28: // "integer" case 36: // "integer"
case 29: // "constant hexstring" case 37: // "constant hexstring"
case 30: // "option name" case 38: // "option name"
case 31: // "ip address" case 39: // "ip address"
value.template destroy< std::string > (); value.template destroy< std::string > ();
break; break;
case 36: // option_code case 44: // option_code
value.template destroy< uint16_t > (); value.template destroy< uint16_t > ();
break; break;
case 41: // nest_level case 50: // nest_level
value.template destroy< uint8_t > (); value.template destroy< uint8_t > ();
break; break;
@@ -1101,31 +1166,35 @@ namespace isc { namespace eval {
super_type::move(s); super_type::move(s);
switch (this->type_get ()) switch (this->type_get ())
{ {
case 37: // option_repr_type case 45: // option_repr_type
value.move< TokenOption::RepresentationType > (s.value); value.move< TokenOption::RepresentationType > (s.value);
break; break;
case 42: // pkt6_field case 46: // pkt4_field
value.move< TokenPkt4::FieldType > (s.value);
break;
case 51: // pkt6_field
value.move< TokenPkt6::FieldType > (s.value); value.move< TokenPkt6::FieldType > (s.value);
break; break;
case 40: // relay6_field case 49: // relay6_field
value.move< TokenRelay6Field::FieldType > (s.value); value.move< TokenRelay6Field::FieldType > (s.value);
break; break;
case 27: // "constant string" case 35: // "constant string"
case 28: // "integer" case 36: // "integer"
case 29: // "constant hexstring" case 37: // "constant hexstring"
case 30: // "option name" case 38: // "option name"
case 31: // "ip address" case 39: // "ip address"
value.move< std::string > (s.value); value.move< std::string > (s.value);
break; break;
case 36: // option_code case 44: // option_code
value.move< uint16_t > (s.value); value.move< uint16_t > (s.value);
break; break;
case 41: // nest_level case 50: // nest_level
value.move< uint8_t > (s.value); value.move< uint8_t > (s.value);
break; break;
@@ -1187,7 +1256,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, 280, 281, 282, 283, 284, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
285, 286 285, 286, 287, 288, 289, 290, 291, 292, 293, 294
}; };
return static_cast<token_type> (yytoken_number_[type]); return static_cast<token_type> (yytoken_number_[type]);
} }
@@ -1300,6 +1369,54 @@ namespace isc { namespace eval {
return symbol_type (token::TOKEN_EXISTS, l); return symbol_type (token::TOKEN_EXISTS, l);
} }
EvalParser::symbol_type
EvalParser::make_PKT4 (const location_type& l)
{
return symbol_type (token::TOKEN_PKT4, l);
}
EvalParser::symbol_type
EvalParser::make_CHADDR (const location_type& l)
{
return symbol_type (token::TOKEN_CHADDR, l);
}
EvalParser::symbol_type
EvalParser::make_HLEN (const location_type& l)
{
return symbol_type (token::TOKEN_HLEN, l);
}
EvalParser::symbol_type
EvalParser::make_HTYPE (const location_type& l)
{
return symbol_type (token::TOKEN_HTYPE, l);
}
EvalParser::symbol_type
EvalParser::make_CIADDR (const location_type& l)
{
return symbol_type (token::TOKEN_CIADDR, l);
}
EvalParser::symbol_type
EvalParser::make_GIADDR (const location_type& l)
{
return symbol_type (token::TOKEN_GIADDR, l);
}
EvalParser::symbol_type
EvalParser::make_YIADDR (const location_type& l)
{
return symbol_type (token::TOKEN_YIADDR, l);
}
EvalParser::symbol_type
EvalParser::make_SIADDR (const location_type& l)
{
return symbol_type (token::TOKEN_SIADDR, l);
}
EvalParser::symbol_type EvalParser::symbol_type
EvalParser::make_SUBSTRING (const location_type& l) EvalParser::make_SUBSTRING (const location_type& l)
{ {
@@ -1373,9 +1490,9 @@ namespace isc { namespace eval {
} }
#line 13 "parser.yy" // lalr1.cc:377 #line 13 "parser.yy" // lalr1.cc:392
} } // isc::eval } } // isc::eval
#line 1379 "parser.h" // lalr1.cc:377 #line 1496 "parser.h" // lalr1.cc:392

View File

@@ -54,6 +54,14 @@ using namespace isc::eval;
TEXT "text" TEXT "text"
HEX "hex" HEX "hex"
EXISTS "exists" EXISTS "exists"
PKT4 "pkt4"
CHADDR "mac"
HLEN "hlen"
HTYPE "htype"
CIADDR "ciaddr"
GIADDR "giaddr"
YIADDR "yiaddr"
SIADDR "siaddr"
SUBSTRING "substring" SUBSTRING "substring"
ALL "all" ALL "all"
COMA "," COMA ","
@@ -73,6 +81,7 @@ using namespace isc::eval;
%type <TokenOption::RepresentationType> option_repr_type %type <TokenOption::RepresentationType> option_repr_type
%type <TokenRelay6Field::FieldType> relay6_field %type <TokenRelay6Field::FieldType> relay6_field
%type <uint8_t> nest_level %type <uint8_t> nest_level
%type <TokenPkt4::FieldType> pkt4_field
%type <TokenPkt6::FieldType> pkt6_field %type <TokenPkt6::FieldType> pkt6_field
%left OR %left OR
@@ -224,7 +233,16 @@ string_expr : STRING
} }
} }
| PKT4 "." pkt4_field
{
TokenPtr pkt4_field(new TokenPkt4($3));
ctx.expression.push_back(pkt4_field);
}
| PKT6 "." pkt6_field
{
TokenPtr pkt6_field(new TokenPkt6($3));
ctx.expression.push_back(pkt6_field);
}
| SUBSTRING "(" string_expr "," start_expr "," length_expr ")" | SUBSTRING "(" string_expr "," start_expr "," length_expr ")"
{ {
TokenPtr sub(new TokenSubstring()); TokenPtr sub(new TokenSubstring());
@@ -235,11 +253,6 @@ string_expr : STRING
TokenPtr conc(new TokenConcat()); TokenPtr conc(new TokenConcat());
ctx.expression.push_back(conc); ctx.expression.push_back(conc);
} }
| PKT6 "." pkt6_field
{
TokenPtr pkt6_field(new TokenPkt6($3));
ctx.expression.push_back(pkt6_field);
}
; ;
option_code : INTEGER option_code : INTEGER
@@ -262,6 +275,36 @@ option_repr_type : TEXT
} }
; ;
pkt4_field : CHADDR
{
$$ = TokenPkt4::CHADDR;
}
| HLEN
{
$$ = TokenPkt4::HLEN;
}
| HTYPE
{
$$ = TokenPkt4::HTYPE;
}
| CIADDR
{
$$ = TokenPkt4::CIADDR;
}
| GIADDR
{
$$ = TokenPkt4::GIADDR;
}
| YIADDR
{
$$ = TokenPkt4::YIADDR;
}
| SIADDR
{
$$ = TokenPkt4::SIADDR;
}
;
start_expr : INTEGER start_expr : INTEGER
{ {
TokenPtr str(new TokenString($1)); TokenPtr str(new TokenString($1));

View File

@@ -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 /// @brief checks if the given token is a substring operator
void checkTokenSubstring(const TokenPtr& token) { void checkTokenSubstring(const TokenPtr& token) {
ASSERT_TRUE(token); ASSERT_TRUE(token);
@@ -585,6 +630,41 @@ TEST_F(EvalContextTest, relay4Error) {
"<string>:1.1-6: relay4 can only be used in DHCPv4."); "<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);
}
// Tests whether message type field in DHCPv6 can be accessed. // Tests whether message type field in DHCPv6 can be accessed.
TEST_F(EvalContextTest, pkt6FieldMsgtype) { TEST_F(EvalContextTest, pkt6FieldMsgtype) {
testPkt6Field("pkt6.msgtype == '1'", TokenPkt6::MSGTYPE, 3); testPkt6Field("pkt6.msgtype == '1'", TokenPkt6::MSGTYPE, 3);
@@ -790,6 +870,7 @@ TEST_F(EvalContextTest, scanErrors) {
checkError("foo", "<string>:1.1: Invalid character: f"); checkError("foo", "<string>:1.1: Invalid character: f");
checkError(" bar", "<string>:1.2: Invalid character: b"); checkError(" bar", "<string>:1.2: Invalid character: b");
checkError("relay[12].hex == 'foo'", "<string>:1.1: Invalid character: r"); 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 // Tests some scanner/parser error cases

View File

@@ -20,6 +20,7 @@
using namespace std; using namespace std;
using namespace isc::dhcp; using namespace isc::dhcp;
using namespace isc::asiolink;
namespace { namespace {
@@ -708,6 +709,86 @@ TEST_F(TokenTest, relay4RAIOnly) {
EXPECT_EQ("false", values_.top()); 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(4, values_.top().size());
uint32_t expected_hlen = htonl(7);
EXPECT_EQ(0, memcmp(&expected_hlen, &values_.top()[0], 4));
// 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(4, values_.top().size());
uint32_t expected_htype = htonl(123);
EXPECT_EQ(0, memcmp(&expected_htype, &values_.top()[0], 4));
// 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 // This test checks if a token representing an == operator is able to
// compare two values (with incorrectly built stack). // compare two values (with incorrectly built stack).
TEST_F(TokenTest, optionEqualInvalid) { TEST_F(TokenTest, optionEqualInvalid) {

View File

@@ -8,6 +8,7 @@
#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 <asiolink/io_address.h>
#include <dhcp/pkt4.h>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <dhcp/pkt6.h> #include <dhcp/pkt6.h>
#include <cstring> #include <cstring>
@@ -124,6 +125,77 @@ OptionPtr TokenRelay4Option::getOption(const Pkt& pkt) {
return (rai->getOption(option_code_)); 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:
// Pad the uint8_t field to 4 bytes.
binary.push_back(0);
binary.push_back(0);
binary.push_back(0);
binary.push_back(pkt4.getHlen());
break;
case HTYPE:
// Pad the uint8_t field to 4 bytes.
binary.push_back(0);
binary.push_back(0);
binary.push_back(0);
binary.push_back(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 void
TokenEqual::evaluate(const Pkt& /*pkt*/, ValueStack& values) { TokenEqual::evaluate(const Pkt& /*pkt*/, ValueStack& values) {

View File

@@ -288,6 +288,61 @@ protected:
virtual OptionPtr getOption(const Pkt& pkt); 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, padded to 4 octets)
/// - htype (hardware address type, padded to 4 octets)
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) /// @brief Token that represents equality operator (compares two other tokens)
/// ///
/// For example in the expression option[vendor-class].text == "MSFT" /// For example in the expression option[vendor-class].text == "MSFT"