Net-DHCPv6
view release on metacpan or search on metacpan
lib/Net/DHCPv6/Option/DomainList.pm view on Meta::CPAN
#!/bin/false
# ABSTRACT: Domain Search List option (code 24) -- RFC 1035 domain names
# PODNAME: Net::DHCPv6::Option::DomainList
use strictures 2;
package Net::DHCPv6::Option::DomainList;
$Net::DHCPv6::Option::DomainList::VERSION = '0.003';
use Net::DHCPv6::OptionList ();
use Net::DHCPv6::Option ();
use Net::DHCPv6::Constants qw(
$DN_COMPRESS_MASK $DN_LABEL_MASK $OPTION_DOMAIN_LIST
);
use Net::DHCPv6::X::Truncated ();
use Net::DHCPv6::X::BadOption ();
use parent 'Net::DHCPv6::Option';
use Ref::Util qw( is_plain_arrayref );
use namespace::clean;
my $EMPTY = q();
my $MAX_PTR_DEPTH = 255; ## no critic (ValuesAndExpressions::ProhibitMagicNumbers)
sub _encode_domain {
my ( $domain ) = @_;
return chr( 0 ) unless defined $domain && CORE::length( $domain );
my @labels = split m/[.]/, $domain;
return join( $EMPTY, map { pack( 'C', CORE::length ) . $_ } @labels ) . chr( 0 );
}
sub _read_labels_at {
my ( $payload, $offset_ref, $len, $depth ) = @_;
$depth //= 0;
my @labels;
while ( ${$offset_ref} < $len ) {
my $llen = unpack( 'C', substr( $payload, ${$offset_ref}, 1 ) );
if ( $llen == 0 ) {
++${$offset_ref};
last;
}
if ( ( $llen & $DN_COMPRESS_MASK ) == $DN_COMPRESS_MASK ) { ## no critic (Bangs::ProhibitBitwiseOperators ValuesAndExpressions::ProhibitMagicNumbers)
if ( $Net::DHCPv6::Option::FOLLOW_COMPRESSION ) {
Net::DHCPv6::X::Truncated->throw( message => 'Truncated compression pointer' )
if ${$offset_ref} + 2 > $len;
my $ptr =
( ( $llen & $DN_LABEL_MASK ) << 8 ) | unpack( 'C', substr( $payload, ${$offset_ref} + 1, 1 ) ); ## no critic (Bangs::ProhibitBitwiseOperators ValuesAndExpressions::ProhibitMagicNumbers)
Net::DHCPv6::X::BadOption->throw( message => 'Compression pointer out of range' )
if $ptr >= $len;
Net::DHCPv6::X::BadOption->throw( message => 'Compression pointer depth exceeded' )
if $depth > $MAX_PTR_DEPTH;
${$offset_ref} += 2;
my $ptr_ref = \$ptr;
push @labels, _read_labels_at( $payload, $ptr_ref, $len, $depth + 1 );
last;
}
Net::DHCPv6::X::BadOption->throw( message => 'Compression pointer in domain name' );
}
Net::DHCPv6::X::BadOption->throw( message => 'Invalid domain label length' ) if $llen > $DN_LABEL_MASK;
++${$offset_ref};
Net::DHCPv6::X::Truncated->throw( message => 'Truncated domain label' )
if ${$offset_ref} + $llen > $len;
push @labels, substr( $payload, ${$offset_ref}, $llen );
${$offset_ref} += $llen;
}
return @labels;
}
sub _decode_domains {
my ( $payload ) = @_;
my @domain_list;
my $offset = 0;
my $len = CORE::length( $payload );
while ( $offset < $len ) {
my @labels = _read_labels_at( $payload, \$offset, $len );
push @domain_list, @labels ? join( q{.}, @labels ) : $EMPTY;
}
return \@domain_list;
}
sub new {
my ( $class, %args ) = @_;
my $domains = $args{domains} // $args{data} // [];
$domains = [$domains] unless is_plain_arrayref( $domains );
$args{code} = $OPTION_DOMAIN_LIST;
$args{data} = join( $EMPTY, map { _encode_domain( $_ ) } @{$domains} );
my $self = $class->SUPER::new( %args );
$self->{domains} = $domains;
( run in 0.557 second using v1.01-cache-2.11-cpan-71847e10f99 )