How do I prevent ip6 usage on net smtp - perl

My Net::SMTP code on Windows 2012 / StrawberryPerl is crapping out and I think it's because Perl is trying to use IPv6 addresses and my local MS SMTP server isn't running on IPv6. The following works, but if I use "localhost" or the FQDN the Net::SMTP->new() fails and $# contains "Bad address"
my $smtp = Net::SMTP->new('127.0.0.1',
Timeout => 30,
Debug => 1,
);
Also, if I use the FQDN of a remote SMTP server (Windows 2008 / IMail), it works.
Both the local & remote servers have SMTP listening on port 25 only for IPv4.
Is there a way to force IPv4 within my script? I thought about disabling IPv6 within Windows but I read that it isn't recommended. What else can I try to debug this?

You can try forcing the dns resolution to ipv4 with Domain => AF_INET}, i.e.:
my $smtp = Net::SMTP->new('FQDN',
Timeout => 30,
Domain => AF_INET,
Debug => 1,
);
If "Domain" is not given, AF_UNSPEC is assumed, that is, both AF_INET
and AF_INET6 will be both considered when resolving DNS names.
AF_INET6 is prioritary.
SRC: http://www.perlmonks.org/?node_id=1127249

Related

Unable to submit email on port 465 using Net::SMTP module in Perl

I want to submit email on port 465 of my smtp server using the Net::SMTP module(without using Net::SMTP::SSL) in a perl script from client. On Port 465 of my SMTP server, "submissions" service runs, which understands SMTPS.
I have tried to find the way to do this on google. Then used the Net::SMTP::SSL module to make request on port 465. It works fine.
But the documentation for Net::SMTP::SSL recommends using latest version Net::SMTP instead of using Net::SMTP::SSL.
The document clearly states that
Since Net::SMTP v1.28 (2014-10-08), Net::SMTP itself has support for
SMTP over SSL, and also for STARTTLS. Use Net::SMTP, not
Net::SMTP::SSL.
I have updated Net::SMTP module to the latest version 3.11.
Also the document for Net::SMTP also stated clearly that
With IO::Socket::SSL installed it also provides support for implicit
and explicit TLS encryption, i.e. SMTPS or SMTP+STARTTLS.
The part of my perl script code on client ,relevant to the problem mentioned looks like so:
$smtp = Net::SMTP::SSL->new("$mailserver",
Hello => "$localhostname",
Timeout => 60,
Port => "$port", //Port value is 465
Debug => 1);
$smtp->auth($username, $password);
...Remaining script which sets sender, receiver body etc
This works fine. The email gets submitted.
Replacing the above code with :
$smtp = Net::SMTP->new("$mailserver",
Hello => "$localhostname",
Timeout => 60,
Port => "$port", //Port value is 465
Debug => 1);
$smtp->auth($username, $password);
...Remaining script which sets sender, receiver body etc
This fails. The debug logs look like this:
Net::SMTP>>> Net::SMTP(3.11)
Net::SMTP>>> Net::Cmd(3.11)
Net::SMTP>>> Exporter(5.73)
Net::SMTP>>> IO::Socket::INET(1.39)
Net::SMTP>>> IO::Socket(1.39)
Net::SMTP>>> IO::Handle(1.39)
Net::SMTP: Net::Cmd::getline(): unexpected EOF on command channel: at fescommon/mailsend-new.pl line 67.
Can't call method "auth" on an undefined value at fescommon/mailsend-new.pl line 74.
Note: Modules like Net::SMTP, Net::SMTP::SSL, IO::Socket::SSL and others are all updated to the latest version.
Expected Result is that request on "submissions" service listening on port 465 on SMTP server can be made using latest Net::SMTP module, without using Net::SMTP::SSL (because the document claims)
If you want to use smtps (i.e. TLS from start instead TLS after the STARTTLS command) you have to explicitly say so. Net::SMTP does not magically derive this requirement from the port number. From the documentation:
new ( [ HOST ] [, OPTIONS ] )
SSL - If the connection should be done from start with SSL, contrary to later upgrade with starttls. You can use SSL arguments as documented in IO::Socket::SSL, but it will usually use the right arguments already.
Thus, the proper code should be:
$smtp = Net::SMTP->new($mailserver,
SSL => 1, # <<<<<<<<<<<<<<<<<<<<<<<< THIS IS IMPORTANT
Hello => $localhostname,
Timeout => 60,
Port => $port, # Port value is 465
Debug => 1
);

IO::Socket::SSL - establishing client connection

As per the documentation of IO::Socket::SSL (PERL) I understand that if I want to just send command to specific server-program that running on port 9999 on my host, Ican do it this way:
my $cl=IO::Socket::SSL->new("localhost:9999"); # locallost is my real case, anyway
if($cl) {
$cl->connect_SSL or die $#;
# Something about certificates?
$cl->syswrite("Command");
close($cl);
}
But the error I get is: "SSL connect attempt failed with unknown error error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol at blabla.cgi line 888"
The server initialized thi way (in another pl program):
use IO::Socket::SSL;
use Net::WebSocket::Server;
my $CON={};
my #crt=&SSLCerts(); die 'E101' if(#crt==0);
my $ssl=IO::Socket::SSL->new(
Listen => 10000,
Timeout => 45,
LocalPort => 9999,
Proto => 'tcp',
SSL_cert_file => "$EF::Base/ssl/certs/$crt[0][0].crt",
SSL_key_file => "$EF::Base/ssl/keys/$crt[1][0].key"
) or die "E102: $!";
Net::WebSocket::Server->new(
listen => $ssl,
silence_max=> 3600,
tick_period => 5,
on_tick => sub {
# Empty for now
},
on_connect => sub {
my($serv,$conn)=#_; my($cid,$sid);
$conn->on(
handshake => sub {
my($cnc,$hdk)=#_;
my $nsn=$hdk->req->resource_name;
$cid=substr($nsn,4,index($nsn,'&L=')-4);
$CON->{$cid}=$cnc; # Register incomming connection
},
binary => sub {
# Handle incomming message from the client
},
disconnect => sub {
delete $CON->{$cid};
}
);
}
)->start;
Typical Websocket client that is connecting from the browser via "wss://" connects without any trouble.... The server MUST be SSL...
Here I am just trying to do the same from within perl.
What I am doing wrong? Nothing mentioned about certificates in client, only in server - the server is working fine. Maybe configuration? I have purchased SSL certificates and I use them for the server that running ok on that port.
The host is Linux (CentOS - if it matters).
... SSL23_GET_SERVER_HELLO:unknown protocol
This is the kind of error you get if the client tries to do a SSL handshake and the server responds with something which is not SSL. Typically this happens if you connect to a server which is not (properly) SSL enabled (at least not on this port) or requires some plain text to upgrade to SSL (like in case of SMTP STARTTLS and similar).
This kind of error has usually nothing to do with certificates.
This kind of error can only happen if you try to do an SSL handshake on an already established SSL socket but the server does not expect this. This seems to happen in your case:
my $cl=IO::Socket::SSL->new("localhost:9999"); # locallost is my real case, anyway
if($cl) {
$cl->connect_SSL or die $#;
...
The SSL connection is already being established by IO::Socket::SSL->new. This is the same with IO::Socket::INET or similar: if the target is given it will already connect inside new and an additional connect or connect_SSL should not be done. This is also reflected in the documentation and examples.
Since version 2.045 (released 02/2017) IO::Socket::SSL will simply ignore a connect_SSL if the SSL handshake is already done. You are likely using an older version of IO::Socket::SSL where connect_SSL will start a new handshake even if the TLS handshake was already finished. This handshake inside the TLS connection will result in the strange error you see.

Setting up Meteor Email with AWS SMTP

This Meteor server code tries to send email from the server start up.
The steps I followed after reading the AWS docs are:
1) Verify an email address which is also on AWS webMail.
2) Applied to increase sending limits.
3) Created and received SMTP credentials.
Meteor 1.4.4.2
email#1.2.1
//server/main.js
smtp = {
'username': 'from smtp credentials',
'password': 'from smtp credentials',
'host': 'email-smtp.us-east-1.amazonaws.com',
'port': '465',
'auth': true
};
process.env.MAIL_URL = 'smtp://' + encodeURIComponent(smtp.username) + ':' + encodeURIComponent(smtp.password) + '#' + encodeURIComponent(smtp.outgoingServer) + ':' + smtp.outgoingPort;
Meteor.startup(() => {
Email.send({
to: 'my-aws-verified-email#comp.com',
subject: 'sending-to-myselft',
text: 'Just checking if it is working'
});
});
Error: getaddrinfo ENOTFOUND undefined undefined:587
Any idea how to get it to work? thx
edit
After changing the process.env.MAIL_URL value to:
process.env.MAIL_URL = 'smtp://' + encodeURIComponent(smtp.username) +
':' + encodeURIComponent(smtp.password) +
'#' + encodeURIComponent(smtp.host) +
':' + smtp.auth + ':' + smtp.port;
The error now is:
Error: Greeting never received
changing the port to "587" gives a different error:
Error: Mail command failed: 501 Invalid MAIL FROM address provided
telnet email-smtp.us-east-1.amazonaws.com 465
Trying 107.21.244.69...
Connected to ses-smtp-prod-335357831.us-east-1.elb.amazonaws.com.
Escape character is '^]'.
Connection closed by foreign host.
telnet email-smtp.us-east-1.amazonaws.com 2465
Trying 54.221.247.194...
Connected to ses-smtp-prod-335357831.us-east-1.elb.amazonaws.com.
Escape character is '^]'.
Connection closed by foreign host.
telnet email-smtp.us-east-1.amazonaws.com 25
Trying 54.243.106.227...
telnet: connect to address 54.243.106.227: Connection refused
Trying 107.21.244.69...
telnet: connect to address 107.21.244.69: Connection refused
Trying 23.21.91.54...
telnet: connect to address 23.21.91.54: Connection refused
Trying 50.19.94.229...
telnet: connect to address 50.19.94.229: Connection refused
Trying 54.235.77.145...
telnet: connect to address 54.235.77.145: Connection refused
Trying 54.243.97.84...
telnet: connect to address 54.243.97.84: Connection refused
Trying 23.23.104.248...
telnet: connect to address 23.23.104.248: Connection refused
Trying 54.221.247.194...
telnet: connect to address 54.221.247.194: Connection refused
telnet: Unable to connect to remote host
telnet email-smtp.us-east-1.amazonaws.com 587
Trying 54.221.247.194...
Connected to ses-smtp-prod-t5t357831.us-east-1.elb.amazonaws.com.
Escape character is '^]'.
220 email-smtp.amazonaws.com ESMTP SimpleEmailService-1110753669 CalqM0Qfzgny2ooZ0wo5
421 Timeout waiting for data from client.
Connection closed by foreign host.
telnet email-smtp.us-east-1.amazonaws.com 2587
Trying 23.23.104.248...
Connected to ses-smtp-prod-337800831.us-east-1.elb.amazonaws.com.
Escape character is '^]'.
220 email-smtp.amazonaws.com ESMTP SimpleEmailService-20753669yy 4qrIfUj4ApTwkj4ZJUNa
421 Timeout waiting for data from client.
Connection closed by foreign host.
You were troubleshooting two simultaneous issues, and when you fixed one of them, it wasn't obvious that you were making progress, because then you encountered the other.
For outbound email, SES listens on two sets of ports.
STARTTLS on the standard port 587, the traditional (but wrong) port 25, and an unprivileged port 2587.
TLS Wrapper on the standard port 465, and an unprivileged port 2465.
The difference between the two sets is how the SSL (TLS) is negotiated. With STARTTLS, the server talks first and the client asks that the connection switch to encrypted mode... while with TLS Wrapper, the connection starts out with TLS but the client talks first, initiating TLS negotiation.
Clearly, from these descriptions, using a TLS Wrapper port when the client anticipates using STARTTLS will result in a timeout, since both sides are waiting for the other side to talk.
Port 25 is not a winner, since EC2 has aggressive rate limiting enabled by default, to prevent the obvious spam problem that would otherwise happen. You can ask for this to be disabled by submitting a support request, but the simplest solution is to just use port 587.
http://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-connect.html
Then, your client wasn't setting a sender address, since no from address was being specified.

Getting files from Windows host with Perls Net::FTP

The laptops in our company go to the network either about LAN (workplace) or about WLAN (conference room). Depending on how they go to the net, they get from DHCP different IPs.
Certain Perl application on a server, copies files from the client (e.g. laptop above) with Net::FTP. The piece of code looks like this:
# don't wait for ftp-timeout if the host is not reachable
my $alive = Net::Ping::External(host => $clnt_host);
if ($alive) {
$ftp = Net::FTP->new($clnt_host, Debug => 0, Timeout => 200)
or return "Cannot connect to $clnt_host: $#\n";
....
....
}
else {
dbgout(1, "Host $clnt_host unreachable.\n");
$st = "'FTPGETFAILED'";
return ($st);
}
Sometimes the code above doesn't work: Net::Ping::External() returns "alive", but Net::FTP->new() gets a "timeout".
Obviously "FTP" and "ping" resolve the hostname differently.
On the OS ping reslove as follows:
C:\Users\converter>ping -n 1 lap314-034
Ping wird ausgeführt für lap314-034.domain.de [10.140.12.110] mit 32 Bytes Daten:
Antwort von 10.140.12.110: Bytes=32 Zeit=2ms TTL=127
However, "nslookup" returns 2 possibilities:
C:\Users\converter>nslookup lap314-034
Server: domaincontroller.domain.de
Address: 123.123.123.123
Name: lap314-034.domain.de
Addresses: 10.192.3.145
10.140.12.110
The not active IP address is delivered from nslookup at the first place back.
I suppose that Net::FTP also uses this address to connect to the client.
How can I "convince" FTP to use the active DNS entry for the connection?
=============================================================
Thanks for your answers. I followed your suggestions. The solution bases on: http://code.activestate.com/lists/perl-win32-users/32624/
#------------------------------------------------------------------
sub getActiveIP {
#------------------------------------------------------------------
my $hostname = shift;
my $host = (gethostbyname ($hostname))[0] or return undef;
my #addr = gethostbyname ($host);
# delete the first 4 array elements
splice #addr, 0, 4;
foreach (#addr) {
my $IPstr = sprintf ("%s", &inet_ntoa ($_));
my $alive = ping(host => $IPstr);
if ($alive) {
return $IPstr;
}
}
return undef;
}
Nevertheless, I believe that a widespread Perl-library should not make such surprises to the user.
How can I "convince" FTP to use the active DNS entry for the connection?
There is no good way to let Net::FTP decide it.
Instead you should determine it outside of Net::FTP and then use the usable IP address instead of the hostname in Net::FTP.
Maybe you would be able to use only Net::FTP with the new versions (Net::FTP > 3.0) which can use IO::Socket::IP instead of IO::Socket::INET as the underlying module. This module can try all the IP addresses returned for a hostname until it gets a successful connection. But these retries will be done for every connection, that is the control connection and every data transfer. Since the connection to the inactive host only fails after some timeout everything will just be horribly slow.
The solution seems obvious: Get the IP addresses, ping them, figure out which one is live, and use the IP address instead of host name in the Net::FTP constructor.

How configure roundcube to work with imaps?

I recently installed Postfix, Dovecot to setup a mail server on my own VPS ( using this tutorial: Email with Postfix, Dovecot, Mysql)
Imaps server uses port 993 for Authentication, and Postfix uses port 25 to send mails.
In this tutorial, users stored in a Database ( so imaps use mysql to authenticate users).
i'm sure every thing works fine with imaps and postfix , because few days ago i installed Kmail client (on my linux) and receive mails from my server. sending mails also works fine, i sent a mail to Gmail and google received it without a problem (in my "Gmail inbox" not spam folder)
So to get to my Emails from a web mail client, i installed Roundcube on /var/www/mail directory.
I configured Roundcube many times. but each time it gives me this Error:
IMAP Error: Login failed for [me#mydomain] from X.x.X.x . Empty
startup greeting (localhost:993) in
/var/www/mm/program/lib/Roundcube/rcube_imap.php on line 184 (POST
/mm/?_task=login?_task=login&_action=login)
When i do log in from roundcube, imap server says ( in /var/log/mail.log ):
May 20 07:05:16 my-server dovecot: imap-login: Disconnected (no auth
attempts): rip=::1, lip=::1, TLS handshaking: Disconnected
Here is my roundcube config file :
$config['db_dsnw'] = 'mysql://roundcubeuser:myPassword#localhost/roundcubemail';
// ----------------------------------
// IMAP
// ----------------------------------
$config['debug_level'] = 13;
$config['default_host'] = 'ssl://127.0.0.1';
$config['default_port'] = 993;
// ----------------------------------
// SMTP
// ----------------------------------
$config['smtp_server'] = 'ssl://localhost';
What's the problem? i really have no idea what is happening !
Thank you.
I'm using postfix + dovecot + roundcube a few months now and it's working for me. In my configuration, postfix rejects plaintext sessions, so roundcube has to connect with ssl - and it's working.
This is from my main.inc.php. I don't remember editing anything here, it's just the initial config created during the installation.
Now that I'm looking at it, default_port doesn't make any sense, I think it's just ignored.
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
// Supported replacement variables:
// %n - http hostname ($_SERVER['SERVER_NAME'])
// %d - domain (http hostname without the first part)
// %s - domain name after the '#' from e-mail address provided at login screen
// For example %n = mail.domain.tld, %d = domain.tld
// TCP port used for IMAP connections
$rcmail_config['default_port'] = 143;
$rcmail_config['default_host'] = array("ssl://localhost:993");
// TCP port used for IMAP connections
$rcmail_config['default_port'] = 143;
In case the other answer does not work, this is what worked for me. My config.inc.php now contains:
$config['default_host'] = 'ssl://localhost';
$config['default_port'] = 993;
NOTE: using tls://localhost did not work for me. I had to specify ssl:// as the URI scheme.
Via PhpMyAdmin, I also ran this SQL command (all my user accounts are on the same machine that runs RoundCube):
UPDATE `rc_users` SET `mail_host`='ssl://localhost'
I got the port number 993 from running sudo netstat -tulnp in order to determine the port on which Dovecot was listening.