Road to Cisco ACL Parser
id:stereocat:20090720:1248100238 の続き。ちょっとお試し。といっても、本当に Parse::Eyapp の使い方を調べるというレベル。というか、前回やったのひと月前かよ。1ヶ月放置だったか。
use strict; use warnings; use Parse::Eyapp; use Data::Dumper; my $grammar = q{ # grammar head section %{ use lib qw(.); use strict; use warnings; use Data::Dumper; use Regexp::Common qw/number net/; use AclEntry; my $curr; %} # grammar body section %% ## level 1 expr: extended_acl ; ## level 2 extended_acl: ACL acl_number.aclnum permission.perm protocol.prot src_dst_spec.sspec src_dst_spec.dspec protocol_qualifier.protq logging.logg { $curr = AclEntry->new(); $curr->acl_number($aclnum); $curr->permission($perm); $curr->protocol($prot); $curr->src_spec($sspec); $curr->dst_spec($dspec); $curr->protocol_qualifier($protq); $curr->logging($logg); $curr; } ; ## level 3 acl_number: # empty | NUM ; permission: PERMIT | DENY ; protocol: IP | TCP | UDP | ICMP | NUM ; src_dst_spec: HOST ip_addr port_num_spec { { ip => $_[2], mask => '0.0.0.0', port => $_[3] } } | ip_addr wildcard_mask port_num_spec { { ip => $_[1], mask => $_[2], port => $_[3] } } ; protocol_qualifier: # empty | ESTABLISHED ; logging: # empty | LOGGING ; ## level 5 ip_addr: IPv4ADDR ; wildcard_mask: IPv4ADDR ; port_num_spec: # empty | NUM ; %% # grammar tail section ## Lexer sub yylex { my ($p) = shift; for ($p->YYData->{INPUT} ) { m/\G\s+/gc; # print "# $_ pos=", pos(), "\n"; # empty $_ eq '' and return ( '', undef ); # ACL keyword m/\G(access-list)/gc and return ( 'ACL', $1 ); # permission m/\G(permit)/gc and return ('PERMIT', $1); m/\G(deny)/gc and return ('DENY', $1); # protocol m/\G(ip)/gc and return ( 'IP', $1); m/\G(tcp)/gc and return ( 'TCP', $1); m/\G(udp)/gc and return ( 'UDP', $1); m/\G(icmp)/gc and return ( 'ICMP', $1); # protocol-qualifier m/\G(established)/gc and return ( 'ESTABLISHED', $1); # logging m/\G(logging)/gc and return ( 'LOGGING', $1); # host keyword m/\G(host)/gc and return ( 'HOST', $1); # ip address, wildcard-mask m/\G($RE{net}{IPv4}{dec})/gc and return ('IPv4ADDR', $1); # number m/\G($RE{num}{int}{-keep})/gc and return ( 'NUM', $1); # any other m/\G(.)/gcs and return ( $1, $1 ); } return ( '', undef );} ## Error Handler sub yyerror { die "Syntax error near " . ( $_[0]->YYCurval ? $_[0]->YYCurval : "end of file" ) . "\n"; } ## main Routine sub run { my ($self) = shift; $self->YYParse( yylex => \&yylex, yyerror => \&yyerror, #yydebug => 0x01, ); } }; # end grammar ############################################################ Parse::Eyapp->new_grammar( input => $grammar, classname => 'AclParser', firstline => 6 ); my $aclparser = AclParser->new(); print "? "; while (<>) { last if m{^q(?:uit)?}; $aclparser->YYData->{INPUT} = $_; my $ret; eval { $ret = $aclparser->run }; warn $@ if $@; print Dumper $ret if defined $ret; print "? "; }
package AclEntry; use strict; use warnings; use base qw/Class::Accessor::Fast/; __PACKAGE__->mk_accessors( qw/acl_number permission protocol src_spec dst_spec protocol_qualifier logging / ); 1;
実行例
$ perl aclparse.01.bak.pl ? access-list 11 permit tcp 192.168.0.1 0.0.0.255 host 192.168.3.3 $VAR1 = bless( { 'protocol_qualifier' => undef, 'protocol' => 'tcp', 'logging' => undef, 'src_spec' => { 'ip' => '192.168.0.1', 'port' => undef, 'mask' => '0.0.0.255' }, 'permission' => 'permit', 'acl_number' => '11', 'dst_spec' => { 'ip' => '192.168.3.3', 'port' => undef, 'mask' => '0.0.0.0' } }, 'AclEntry' ); ? access-list deny udp host 192.168.0.1 host 192.168.3.3 $VAR1 = bless( { 'protocol_qualifier' => undef, 'protocol' => 'udp', 'logging' => undef, 'src_spec' => { 'ip' => '192.168.0.1', 'port' => undef, 'mask' => '0.0.0.0' }, 'permission' => 'deny', 'acl_number' => undef, 'dst_spec' => { 'ip' => '192.168.3.3', 'port' => undef, 'mask' => '0.0.0.0' } }, 'AclEntry' ); ? q $
とまあ、こんな感じで、ACL を Parse して加工の簡単な形にして出してくれないかなーという目論見だったのだが。まあ、どういう形にするかは要検討だな。Parse 結果を保持する class も今回は適当に作ったのだけど、cpan 探せば何かあるんじゃなかろうか。ACL Parse → ACL Object → ACL操作 → ACL出力 みたいな流れでやれるといいかなあ、くらい。NetAddr::IP とかその辺のオブジェクトでIPアドレスとか保持するようにして重複チェックとか、最適化とかに持っていけるような状態に…なったらいいなあ、と。
もうちょっと Parse::Eyapp 使い方調べないといけないな。画面でドキュメント読むのしんどいので今度印刷してこよう。
それにしても、ACL の文法ってどう組むのがいいんだろう。今回はお試しなので any とかのワードすら入れてないし、port 指定についても演算子入れるの忘れてたり。その辺ってどこかにまとまった資料がないのだろうか? とりあえずいまは
と、前回作った acl syntax checker の syntax tree を見ていたのだが。あ、あと
- 作者: ジェフシダヤオ,Jeff Sedayao,岡利章,生田りえ子
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2002/03
- メディア: 単行本
- 購入: 2人 クリック: 9回
- この商品を含むブログ (3件) を見る