view release on metacpan or search on metacpan
lib/BIND/Conf_Parser.pm view on Meta::CPAN
16171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576sub
choke {
shift
;
confess
"parse error: "
,
@_
}
sub
set_toke($$;$) {
my
(
$self
,
$token
,
$data
) =
@_
;
$self
->{_token} =
$token
;
$self
->{_data} =
$data
;
}
sub
where($;$) {
my
$self
=
shift
;
if
(
@_
) {
$self
->{_file} .
":"
.
$_
[0]
}
else
{
$self
->{_file} .
":"
.
$self
->{_line}
}
}
sub
read_line($) {
my
$self
=
shift
;
$self
->{_line}++;
chomp
(
$self
->{_curline} =
$self
->{_fh}->getline);
}
sub
check_comment($) {
my
$self
=
shift
;
for
my
$i
(
$self
->{_curline}) {
$i
=~m:\G
#.*:gc and last;
$i
=~m:\G//.*:gc and
last
;
if
(
$i
=~m:\G/\*:gc) {
my
(
$line
) =
$self
->{_line};
until
(
$i
=~m:\G.*?\*/:gc) {
$self
->read_line ||
$i
ne
""
||
$self
->choke(
"EOF in comment starting at "
,
$self
->where(
$line
));
}
}
return
0
}
return
1
}
sub
lex_string($) {
my
$self
=
shift
;
my
(
$s
,
$line
);
$line
=
$self
->{_line};
$s
=
""
;
LOOP:
for
my
$i
(
$self
->{_curline}) {
# the lexer in bind doesn't implement backslash escapes of any kind
# $i=~/\G([^"\\]+)/gc and do { $s .= $1; redo LOOP };
# $i=~/\G\\(["\\])/gc and do { $s .= $1; redo LOOP };
$i
=~/\G([^"]+)/gc and
do
{
$s
.= $1;
redo
LOOP };
$i
=~/\G"/gc and
$self
->set_toke(STRING,
$s
),
return
;
lib/BIND/Conf_Parser.pm view on Meta::CPAN
78798081828384858687888990919293949596979899100101102103104105106107108
if
(
$self
->read_line) {
$s
.=
"\n"
;
}
elsif
(
$i
eq
""
) {
$self
->choke(
"EOF in quoted string starting at "
,
$self
->where(
$line
));
}
redo
LOOP;
}
}
sub
lex_ident($$) {
my
$self
=
shift
;
my
(
$i
) =
@_
;
while
(!
$self
->check_comment &&
$self
->{_curline} =~ m:\G([^/"*!{};\s]+):gc) {
$i
.= $1;
}
$self
->set_toke(WORD,
$i
);
}
sub
lex_ipv4($$) {
my
$self
=
shift
;
my
(
$i
) =
@_
;
LOOP:
for
my
$j
(
$self
->{_curline}) {
$self
->check_comment and
last
LOOP;
$j
=~/\G(\d+)/gc and
do
{
$i
.= $1;
redo
LOOP };
$j
=~/\G(\.\.)/gc ||
$j
=~m:\G([^./
"*!{};\s]+):gc and $self->lex_ident("
$i
$1"),
return
;
$j
=~/\G\./gc and
do
{
$i
.=
"."
;
redo
LOOP };
}
my
(
$dots
);
lib/BIND/Conf_Parser.pm view on Meta::CPAN
112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
return
}
if
(
$dots
== 1) {
$i
.=
".0.0"
;
}
elsif
(
$dots
== 2) {
$i
.=
".0"
;
}
$self
->set_toke(IPADDR,
$i
);
}
sub
lex_number($$) {
my
$self
=
shift
;
my
(
$n
) =
@_
;
LOOP:
for
my
$i
(
$self
->{_curline}) {
$self
->check_comment and
last
LOOP;
$i
=~/\G(\d+)/gc and
do
{
$n
.= $1;
redo
LOOP };
$i
=~/\G\./gc and
$self
->lex_ipv4(
"$n."
),
return
;
$i
=~m:\G([^/
"*!{};\s]+):gc and $self->lex_ident("
$n
$1"),
return
;
}
$self
->set_toke(NUMBER,
$n
);
}
sub
lex($) {
my
$self
=
shift
;
OUTER:
while
(1) {
for
my
$i
(
$self
->{_curline}) {
INNER: {
$self
->check_comment and
last
INNER;
$i
=~/\G\s+/gc and
redo
;
$i
=~m:\G([*/!{};]):gc and
$self
->set_toke($1),
last
OUTER;
$i
=~/\G"/gc and
$self
->lex_string(),
last
OUTER;
$i
=~/\G(\d+)/gc and
$self
->lex_number($1),
last
OUTER;
$i
=~/\G(.)/gc and
$self
->lex_ident($1),
last
OUTER;
}
$i
=~/\G\Z/gc or
$self
->choke(
"Unknown character at "
,
$self
->where);
$self
->read_line ||
$i
ne
""
or
$self
->set_toke(ENDoFILE),
last
OUTER;
} }
return
$self
;
}
sub
t2d($) {
my
$self
=
shift
;
$self
->{_token} eq WORD and
return
qq('$self->{_data}')
;
$self
->{_token} eq STRING and
return
qq("$self->{_data}")
;
$self
->{_token} eq NUMBER ||
$self
->{_token} eq IPADDR and
return
$self
->{_data};
$self
->{_token} eq ENDoFILE and
return
"<end of file>"
;
return
qq('$self->{_token}')
;
}
sub
t2n($;$) {
my
(
$token
,
$need_article
);
my
(
$map
) = {
WORD , [
an
=>
"identifier"
],
STRING , [
a
=>
"string"
],
NUMBER , [
a
=>
"number"
],
IPADDR , [
an
=>
"IP address"
],
ENDoFILE , [
"End of File"
],
'*'
, [
an
=>
"asterisk"
],
'!'
, [
an
=>
"exclamation point"
],
'{'
, [
an
=>
"open brace"
],
lib/BIND/Conf_Parser.pm view on Meta::CPAN
173174175176177178179180181182183184185186187188189190191192193
';'
, [
a
=>
"semicolon"
],
}->{
$token
};
return
"Fwuh? `$token'"
unless
$map
;
if
(
$need_article
) {
join
(
" "
, @{
$map
})
}
else
{
$map
->[-1]
}
}
sub
expect($$$;$) {
my
$self
=
shift
;
my
(
$token
,
$mess
,
$nolex
) =
@_
;
$self
->lex
unless
$nolex
;
$token
= [
$token
]
unless
ref
$token
;
foreach
(@{
$token
}) {
if
(
ref
$_
) {
next
unless
$self
->{_token} eq WORD;
foreach
(
@$_
) {
return
if
$_
eq
$self
->{_data};
}
lib/BIND/Conf_Parser.pm view on Meta::CPAN
201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
$token
= ${
$token
}[0];
$token
= WORD
if
ref
$token
;
$self
->choke(
"Expected "
, t2n(
$token
, 1),
", saw "
,
$self
->t2d,
" $mess at "
,
$self
->where);
}
else
{
$self
->choke(
"Unexpected "
, t2n(
$self
->{_token}),
" ("
,
$self
->t2d,
") $mess at "
,
$self
->where);
}
}
sub
open_file($$) {
my
$self
=
shift
;
my
(
$file
) =
@_
;
$self
->{_fh} = IO::File->new(
$file
,
"r"
)
or croak
"Unable to open $file for reading: $!"
;
$self
->{_file} =
$file
;
}
sub
parse_bool($$) {
my
(
$self
,
$mess
) =
@_
;
$self
->expect([ WORD, STRING, NUMBER ],
$mess
);
my
(
$value
) = {
"yes"
=> 1,
"no"
=> 0,
"true"
=> 1,
"false"
=> 0,
"1"
=> 1,
"0"
=> 0,
}->{
$self
->{_data}};
return
$value
if
defined
$value
;
$self
->choke(
"Expected a boolean, saw `"
,
$self
->{_data},
"' at "
,
$self
->where);
}
sub
parse_addrmatchlist($$;$) {
my
(
$self
,
$mess
,
$nolex
) =
@_
;
$self
->expect(
'{'
,
$mess
,
$nolex
);
my
(
@items
,
$negated
,
$data
);
while
(1) {
$negated
= 0;
$self
->expect([ IPADDR, NUMBER, WORD, STRING,
'!'
,
'{'
,
'}'
],
$mess
);
last
if
$self
->{_token} eq
'}'
;
if
(
$self
->{_token} eq
'!'
) {
$negated
= 1;
$self
->expect([ IPADDR, NUMBER, WORD, STRING,
'{'
],
lib/BIND/Conf_Parser.pm view on Meta::CPAN
259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
push
@items
, [
$negated
,
$data
];
redo
# we already slurped the ';'
}
$self
->expect(NUMBER,
"following `/'"
);
push
@items
, [
$negated
,
$data
,
$self
->{_data} ];
}
continue
{
$self
->expect(
';'
,
$mess
);
}
return
\
@items
}
sub
parse_addrlist($$) {
my
(
$self
,
$mess
) =
@_
;
$self
->expect(
'{'
,
$mess
);
my
(
@addrs
);
while
(1) {
$self
->expect([ IPADDR,
'}'
],
$mess
);
last
if
$self
->{_token} eq
'}'
;
push
@addrs
,
$self
->{_data};
$self
->expect(
';'
,
"reading address list"
);
}
return
\
@addrs
;
# return \@addrs if @addrs;
# $self->choke("Expected at least one IP address, saw none at ",
# $self->where);
}
sub
parse_size($$) {
my
(
$self
,
$mess
) =
@_
;
$self
->expect([ WORD, STRING ],
$mess
);
my
(
$data
) =
$self
->{_data};
if
(
$data
=~ /^(\d+)([kmg])$/i) {
return
$1 * {
'k'
=> 1024,
'm'
=> 1024*1024,
'g'
=> 1024*1024*1024,
}->{
lc
($2)};
}
$self
->choke(
"Expected size string, saw `$data' at "
,
$self
->where);
}
sub
parse_forward($$) {
my
(
$self
,
$mess
) =
@_
;
$self
->expect([[
qw(only first)
]],
$mess
);
return
$self
->{_data};
}
sub
parse_transfer_format($$) {
my
(
$self
,
$mess
) =
@_
;
$self
->expect([[
qw(one-answer many-answers)
]],
$mess
);
return
$self
->{_data};
}
sub
parse_check_names($$) {
my
(
$self
,
$mess
) =
@_
;
$self
->expect([[
qw(warn fail ignore)
]],
$mess
);
return
$self
->{_data};
}
sub
parse_pubkey($$) {
my
(
$self
,
$mess
) =
@_
;
my
(
$flags
,
$proto
,
$algo
);
$self
->expect([ NUMBER, WORD, STRING ],
$mess
);
$flags
=
$self
->{_data};
if
(
$self
->{_token} ne NUMBER) {
$flags
=
oct
(
$flags
)
if
$flags
=~ /^0/;
}
$self
->expect(NUMBER,
$mess
);
$proto
=
$self
->{_data};
$self
->expect(NUMBER,
$mess
);
$algo
=
$self
->{_data};
$self
->expect(STRING,
$mess
);
return
[
$flags
,
$proto
,
$algo
,
$self
->{_data} ];
}
sub
parse_logging_category($) {
my
$self
=
shift
;
$self
->expect([ WORD, STRING ],
"following `category'"
);
my
(
$name
) =
$self
->{_data};
$self
->expect(
'{'
,
"following `category $name'"
);
my
(
@names
);
while
(1) {
$self
->expect([ WORD, STRING,
'}'
],
"reading category `$name'"
);
last
if
$self
->{_token} eq
'}'
;
push
@names
,
$self
->{_data};
$self
->expect(
';'
,
"reading category `$name'"
);
}
$self
->expect(
';'
,
"to finish category `$name'"
);
$self
->handle_logging_category(
$name
, \
@names
);
}
sub
parse_logging_channel($) {
my
$self
=
shift
;
$self
->expect([ WORD, STRING ],
"following `channel'"
);
my
(
$name
) =
$self
->{_data};
$self
->expect(
'{'
,
"following `channel $name'"
);
my
(
%options
,
$temp
);
while
(1) {
$self
->expect([ [
qw(file syslog null severity print-category
print-severity print-time)
],
'}'
],
"reading channel `$name'"
);
last
if
$self
->{_token} eq
'}'
;
lib/BIND/Conf_Parser.pm view on Meta::CPAN
404405406407408409410411412413414415416417418419420421422423424
}
}
}
}
continue
{
$self
->expect(
';'
,
"reading channel `$name'"
);
}
$self
->expect(
';'
,
"to finish channel `$name'"
);
$self
->handle_logging_channel(
$name
, \
%options
);
}
sub
parse_logging($) {
my
$self
=
shift
;
$self
->expect(
'{'
,
"following `logging'"
);
while
(1) {
$self
->expect([ [
qw(category channel)
],
'}'
],
"reading logging options"
);
last
if
$self
->{_token} eq
'}'
;
if
(
$self
->{_data} eq
"category"
) {
$self
->parse_logging_category;
}
else
{
# channel
$self
->parse_logging_channel;
lib/BIND/Conf_Parser.pm view on Meta::CPAN
556557558559560561562563564565566567568569570571572573574575576
}
# Must be 'order'
$self
->expect(WORD,
"following `order'"
);
push
(
@items
, [
$class
,
$type
,
$name
,
$self
->{_data}]);
$self
->expect(
';'
,
$mess
);
}
return
\
@items
;
},
);
sub
parse_key($) {
my
$self
=
shift
;
$self
->expect([ WORD, STRING ],
"following `key'"
);
my
(
$key
,
$algo
,
$secret
);
$key
=
$self
->{_data};
$self
->expect(
'{'
,
"following key name `$key'"
);
$self
->expect([[
qw(algorithm secret)
]],
"reading key $key"
);
if
(
$self
->{_data} eq
"secret"
) {
$self
->expect([ WORD, STRING ],
"reading secret for key `$key'"
);
$secret
=
$self
->{_data};
$self
->expect(
';'
,
"reading key `$key'"
);
lib/BIND/Conf_Parser.pm view on Meta::CPAN
584585586587588589590591592593594595596597598599600601602603604
$self
->expect([[
"secret"
]],
"reading key `$key'"
);
$self
->expect([ WORD, STRING ],
"reading secret for key `$key'"
);
$secret
=
$self
->{_data};
}
$self
->expect(
';'
,
"reading key `$key'"
);
$self
->expect(
'}'
,
"reading key `$key'"
);
$self
->expect(
';'
,
"to finish key `$key'"
);
$self
->handle_key(
$key
,
$algo
,
$secret
);
}
sub
parse_controls($) {
my
$self
=
shift
;
$self
->expect(
'{'
,
"following `controls'"
);
while
(1) {
$self
->expect([ [
qw(inet unix)
],
';'
],
"reading `controls'"
);
last
if
$self
->{_token} eq
';'
;
if
(
$self
->{_data} eq
"inet"
) {
my
(
$addr
,
$port
);
$self
->expect([ IPADDR,
'*'
],
"following `inet'"
);
$addr
=
$self
->{_token} eq
'*'
? 0 :
$self
->{_data};
$self
->expect([[
"port"
]],
"following inet address"
);
lib/BIND/Conf_Parser.pm view on Meta::CPAN
619620621622623624625626627628629630631632633634635636637638639
$owner
=
$self
->{_data};
$self
->expect([[
"group"
]],
"following owner name"
);
$self
->expect(NUMBER,
"following `group'"
);
$self
->handle_control(
"unix"
,
[
$path
,
$perm
,
$owner
,
$self
->{_data} ]);
}
}
$self
->expect(
'}'
,
"finishing `controls'"
);
}
sub
parse_server($) {
my
$self
=
shift
;
$self
->expect(IPADDR,
"following `server'"
);
my
(
$addr
,
%options
);
$addr
=
$self
->{_data};
$self
->expect(
'{'
,
"following `server $addr'"
);
while
(1) {
$self
->expect([ [
qw(bogus support-ixfr transfers
transfer-format keys)
] ,
'}'
],
"reading server `$addr'"
);
last
if
$self
->{_token} eq
'}'
;
lib/BIND/Conf_Parser.pm view on Meta::CPAN
665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
push
@keys
,
$self
->{_data};
}
$options
{
"keys"
} = \
@keys
;
}
continue
{
$self
->expect(
';'
,
"reading server `$addr'"
);
}
$self
->expect(
';'
,
"to finish server `$addr'"
);
$self
->handle_server(
$addr
, \
%options
);
}
sub
parse_trusted_keys($) {
my
$self
=
shift
;
$self
->expect(
'{'
,
"following `trusted-keys'"
);
my
(
$domain
,
$flags
,
$proto
,
$algo
);
while
(1) {
$self
->expect([ WORD,
'}'
],
"while reading key for `trusted-keys'"
);
last
if
$self
->{_token} eq
'}'
;
$domain
=
$self
->{_data};
$self
->handle_trusted_key(
$domain
,
$self
->parse_pubkey(
"while reading key for `trusted-keys'"
));
}
$self
->expect(
';'
,
"to finish trusted-keys"
);
}
sub
parse_zone($) {
my
$self
=
shift
;
my
(
$name
,
$class
);
$self
->expect([ WORD, STRING ],
"following `zone'"
);
$name
=
$self
->{_data};
$self
->expect([ WORD, STRING,
'{'
,
';'
],
"following `zone $name'"
);
if
(
$self
->{_token} eq
';'
) {
$self
->handle_empty_zone(
$name
,
'in'
);
return
}
elsif
(
$self
->{_token} eq
'{'
) {
$class
=
'in'
;
lib/BIND/Conf_Parser.pm view on Meta::CPAN
756757758759760761762763764765766767768769770771772773774775776
$self
->expect(
';'
,
"reading zone `$name'"
);
}
$self
->expect(
';'
,
"to finish zone `$name'"
);
if
(!
exists
$options
{type}) {
$self
->handle_empty_zone(
$name
,
$class
, \
%options
);
}
else
{
$self
->handle_zone(
$name
,
$class
,
$options
{type}, \
%options
);
}
}
sub
parse_options($) {
my
$self
=
shift
;
$self
->expect(
'{'
,
"following `options'"
);
my
(
$type
,
$option
,
$arg
,
$ate_semi
,
$did_handle_option
);
while
(1) {
$self
->expect([ WORD,
'}'
],
"reading options"
);
last
if
$self
->{_token} eq
'}'
;
$option
=
$self
->{_data};
$type
=
$opt_table
{
$option
};
$ate_semi
=
$did_handle_option
= 0;
if
(
ref
$type
) {
lib/BIND/Conf_Parser.pm view on Meta::CPAN
781782783784785786787788789790791792793794795796797798799800801
$arg
=
$self
->{_data};
}
$self
->expect(
';'
,
"following argument for option `$option'"
)
unless
$ate_semi
;
$self
->handle_option(
$option
,
$arg
)
unless
$did_handle_option
;
}
$self
->expect(
';'
,
"to finish options"
);
}
sub
parse_conf() {
my
$self
=
shift
;
$self
->{_curline} =
''
;
$self
->{_flags} = { };
while
(1) {
$self
->expect([ ENDoFILE, WORD ],
"at beginning of statement"
);
if
(
$self
->{_token} eq ENDoFILE) {
if
(
$self
->{_fhs} && @{
$self
->{_fhs}}) {
my
(
$pos
);
(
@$self
{
qw(_fh _file _curline)
},
$pos
) =
@{
pop
@{
$self
->{_fhs}} };