#!/usr/bin/perl # $Id: dns_srv_imap,v 1.5 2016/08/15 01:24:20 gilles Exp gilles $ use strict ; use warnings ; use English ; use Test::More ; use Net::DNS ; foreach my $email ( @ARGV ) { my $domain = domain_name_of( $email ) ; print "Domain for email $email: $domain\n" ; my ( $host, $port ) = host_port_from_lookup_srv( '_imaps._tcp.' . $domain ) ; $host ||= q{} ; $port ||= q{} ; print "IMAPS server name and port for $email: $host $port\n" ; ( $host, $port ) = host_port_from_lookup_srv( '_imap._tcp.' . $domain ) ; $host ||= q{} ; $port ||= q{} ; print "IMAP server name and port for $email: $host $port\n" ; } tests_server_name_from_srv_string( ) ; tests_server_port_from_srv_string( ) ; tests_domain_name_of( ) ; tests_host_port_ssl_from_user( ) ; done_testing( ) ; my $debug = 1 ; sub host_port_ssl_from_user { my $user = shift @ARG ; if ( ! $user ) { return ; } my $domain = domain_name_of( $user ) ; if ( ! $domain ) { return ; } my ( $host, $port ) = host_port_from_lookup_srv( qq{_imaps._tcp.$domain} ) ; my $ssl = 1 ; if ( $host and $port ) { return ( $host, $port, $ssl ) ; } # fallback to imap in clear $ssl = 0 ; ( $host, $port ) = host_port_from_lookup_srv( qq{_imap._tcp.$domain} ) ; if ( $host and $port ) { return ( $host, $port, $ssl ) ; } return ; } sub tests_host_port_ssl_from_user { is( undef, host_port_ssl_from_user( ), 'host_port_ssl_from_user: no args => undef' ) ; is_deeply( [qw( imap.gmail.com. 993 1 )], [host_port_ssl_from_user( 'gilles.lamiral@gmail.com' )], 'host_port_ssl_from_user: gilles.lamiral@gmail.com => imap.gmail.com. 993 1 (ssl)' ) ; } sub host_port_from_lookup_srv { my $request = shift @ARG ; my $lookup = lookup_srv_string( $request ) ; if ( ! $lookup ) { return ; } my $host = server_name_from_srv_string( $lookup ) ; my $port = server_port_from_srv_string( $lookup ) ; if( $host and $port ) { return ( $host, $port ) ; } else { return ; } } sub domain_name_of_email { my $email = shift ; return( undef ) if ( not $email ) ; my $domain ; if ( $email =~ /^.*@([^@]+)$/ ) { $domain = $1 ; $debug and print "domain: $domain\n" ; return( $domain ) ; } return ; } sub domain_name_of { my $email = shift ; return( undef ) if ( not $email ) ; my $domain = domain_name_of_email( $email ) ; if ( ! $domain ) { $domain = $email ; } return( $domain ) ; } sub tests_domain_name_of { ok( not( domain_name_of( '' ) ), 'domain_name_of: void => undef' ) ; ok( not( domain_name_of( ) ), 'domain_name_of: undef => undef' ) ; ok( 'foo' eq domain_name_of( 'foo' ), 'domain_name_of: foo => foo' ) ; #ok( 'foo' eq domain_name_of( 'foo ' ), 'domain_name_of: foo => foo' ) ; #ok( 'foo' eq domain_name_of( 'foo ' ), 'domain_name_of: foo => foo' ) ; ok( 'example.com' eq domain_name_of( 'foo@example.com' ), 'domain_name_of: foo@example.com => example.com' ) ; ok( 'example.com' eq domain_name_of( '@foo@example.com' ), 'domain_name_of: @foo@example.com => example.com' ) ; ok( 'example.com' eq domain_name_of( 'bar@foo@example.com' ), 'domain_name_of: bar@foo@example.com => example.com' ) ; } sub lookup_srv_string { my $name = shift ; my $resolver = new Net::DNS::Resolver( ) ; my $reply = $resolver->query( $name, 'SRV' ) ; my $string ; if ( $reply ) { #($reply->answer)[0]->print; foreach my $rr ( $reply->answer ) { $debug and print 'name: ' . $rr->name . "\n" ; $debug and print 'class: ' . $rr->class . "\n" ; $debug and print 'type: ' . $rr->type . "\n" ; $debug and print 'ttl: ' . $rr->ttl . "\n" ; $debug and print 'string: ' . $rr->string . "\n" ; next if ( 'SRV' ne $rr->type ) ; next if ( not( $rr->string ) ) ; $string = $rr->string ; return( $string ) ; } } else { print "Query failed SRV for domain $name: ", $resolver->errorstring, "\n" ; return( undef ) ; } return( $string ) ; } sub server_name_from_srv_string { my $srv_string = shift ; return( undef ) if ( not $srv_string ) ; my $server_name = (split( /\s+/ , $srv_string ) )[7] ; return( undef ) if ( '.' eq $server_name ) ; return( $server_name ) ; } sub tests_server_name_from_srv_string { ok( not( server_name_from_srv_string( '' ) ), 'server_name_from_srv_string: void' ) ; ok( not( server_name_from_srv_string( ) ), 'server_name_from_srv_string: undef' ) ; ok( 'imap.gmail.com.' eq server_name_from_srv_string( '_imaps._tcp.gmail.com. 82466 IN SRV 5 0 993 imap.gmail.com.' ), 'server_name_from_srv_string: _imaps._tcp.gmail.com. => imap.gmail.com.' ) ; ok( not( server_name_from_srv_string( '_imap._tcp.gmail.com. 81999 IN SRV 0 0 0 .' ) ), 'server_name_from_srv_string: _imap._tcp.gmail.com. => undef' ) ; return( ) ; } sub server_port_from_srv_string { my $srv_string = shift ; return( undef ) if ( not $srv_string ) ; my $server_port = (split( /\s+/ , $srv_string ) )[6] ; return( undef ) if ( 0 == $server_port ) ; return( $server_port ) ; } sub tests_server_port_from_srv_string { ok( not( server_port_from_srv_string( '' ) ), 'server_port_from_srv_string: void' ) ; ok( not( server_port_from_srv_string( ) ), 'server_port_from_srv_string: undef' ) ; ok( '993' eq server_port_from_srv_string( '_imaps._tcp.gmail.com. 82466 IN SRV 5 0 993 imap.gmail.com.' ), 'server_port_from_srv_string: _imaps._tcp.gmail.com. => 993' ) ; ok( not( server_port_from_srv_string( '_imap._tcp.gmail.com. 81999 IN SRV 0 0 0 .' ) ), 'server_port_from_srv_string: _imap._tcp.gmail.com. => undef' ) ; return( ) ; }