Net-DNS-Dynamic-Proxyserver
view release on metacpan or search on metacpan
lib/Net/DNS/Dynamic/Proxyserver.pm view on Meta::CPAN
If you'd like to anwer DNS queries from entries in your /etc/hosts file, then
define this argument like so:
my $proxy = Net::DNS::Dynamic::Proxyserver->new( ask_etc_hosts => { ttl => 3600 } );
The only argument that can be passed to 'ask_etc_hosts' is the TTL (time to life) for
the response.
If 'ask_etc_hosts' is not defined, no queries to /etc/hosts will be made.
If you make changes to your /etc/hosts file, you can send your script a
signal HUP and it will re-read the file on the fly.
=head2 ask_sql HashRef
If you'd like to answer DNS queries from entries in your SQL database, then define
this argument like so:
my $proxy = Net::DNS::Dynamic::Proxyserver->new( ask_sql => {
ttl => 60,
dsn => 'DBI:mysql:database=db_name;host=localhost;port=3306',
user => 'my_user',
pass => 'my_password',
statement => "SELECT ip FROM hosts WHERE hostname='{qname}' AND type='{qtype}'"
} );
The 'ttl' specifies the TTL (time to life) for the DNS response. Setting this to a
low value will tell the client to ask you again after the TTL time has passed by;
which also means some higher load for your dns-proxy-server.
The 'dsn' is the 'data source name' for the DBI module. This information is used
to connect to your SQL database. You can use every flavour of SQL database that
is supported by DBI and a DBD::* module, like MySQL, PostgreSQL, SQLite, Oracle, etc...
Please have a look at the manual page of DBI and DBD::* to see how a dsn looks like
and which options it could contain.
The 'user' and 'pass' is the username and password for the connection to the database. If
you use SQLite, just leave the values empty (user => '', pass => ''). Also make sure, the
SQLite database file can be accessed (read/write) with the defined uid/gid!
The 'statement' is a SELECT statement, which must return the IP address for the
given query name (qname) and query type (qtype, like 'A' or 'MX'). The placeholders
{qname} and {qtype} will be replaced by the actual query name and type. Your statement
must return the IP address as the first column in the result.
If 'ask_sql' is not defined, no queries to a database will be made.
=cut
subtype 'Net.DNS.Dynamic.Proxyserver.ValidSQLArguments'
=> as 'HashRef'
=> where { $_->{dsn} && $_->{user} && $_->{pass} && $_->{statement} }
=> message { "Mandatory elements missing in argument 'ask_sql': dsn, user, pass, statement" };
has debug => ( is => 'ro', isa => 'Int', required => 0, default => 0 );
has host => ( is => 'ro', isa => 'Str', required => 0, default => '*' );
has port => ( is => 'ro', isa => 'Int', required => 0, default => 53 );
has uid => ( is => 'ro', isa => 'Int', required => 0 );
has gid => ( is => 'ro', isa => 'Int', required => 0 );
has ask_etc_hosts => ( is => 'ro', isa => 'HashRef', required => 0 );
has ask_sql => ( is => 'ro', isa => 'Net.DNS.Dynamic.Proxyserver.ValidSQLArguments', required => 0 );
has addrs => ( is => 'rw', isa => 'HashRef', init_arg => undef );
has forwarders => ( is => 'rw', isa => 'ArrayRef', required => 0, init_arg => 'nameservers' );
has forwarders_port => ( is => 'ro', isa => 'Int', required => 0, init_arg => 'nameservers_port' );
has dbh => ( is => 'rw', isa => 'Object', init_arg => undef );
has nameserver => ( is => 'rw', isa => 'Net::DNS::Nameserver', init_arg => undef );
has resolver => ( is => 'rw', isa => 'Net::DNS::Resolver', init_arg => undef );
sub BUILD {
my ( $self ) = shift;
# initialize signal handlers
#
$SIG{KILL} = sub { $self->signal_handler(@_) };
$SIG{QUIT} = sub { $self->signal_handler(@_) };
$SIG{TERM} = sub { $self->signal_handler(@_) };
$SIG{INT} = sub { $self->signal_handler(@_) };
$SIG{HUP} = sub { $self->read_config() };
# slurp in /etc/hosts and /etc/resolv.conf
#
$self->read_config();
# initialize nameserver object
#
my $ns = Net::DNS::Nameserver->new(
LocalAddr => $self->host,
LocalPort => $self->port,
ReplyHandler => sub { $self->reply_handler(@_); },
Verbose => ($self->debug > 1 ? 1 : 0)
);
$self->nameserver( $ns );
# initialize resolver object
#
my $res = Net::DNS::Resolver->new(
nameservers => [ @{$self->forwarders} ],
port => $self->forwarders_port || 53,
recurse => 1,
debug => ($self->debug > 2 ? 1 : 0),
);
$self->resolver( $res );
# change the effective user id and group id
#
$> = $self->uid if $self->uid;
$) = $self->gid if $self->gid;
}
sub run {
my ( $self ) = shift;
$self->log("listening for DNS queries on address " . $self->host . " and port " . $self->port, 1);
( run in 0.608 second using v1.01-cache-2.11-cpan-9581c071862 )