SMTP via a SSH tunnel
Posted by Utumno on Thu 18 Jan 2007 at 12:53
I've got an account on a FreeBSD machine on which I've got 12 years' worth of email, and a beautiful spamassassin / procmail setup. All my friends know the account ( let's call it 'utumno@smarthost.com' and the server 'smarthost.com' ) so I'd really hate having to change it. I use fetchmail/procmail combo to download mail through IMAP, and sylpheed-claws-gtk2 to read it.
However, now I am working overseas, and recently smarthost.com decided to deny all SMTP relay ( including SMTP AUTH ) from abroad.
Way out #1 - use local smarthost
This solution is actually quite tricky because I really want to keep sending mails from 'utumno@smarthost.com'. If I simply try using 'smtp.my.isp.com' with that 'from' address, Sender Policy Framework fails. This makes some receving servers move my mails directly to the 'spam' folder, others - deny the mail outright.Fixing that issue would require adding 'smtp.my.isp.com' to the SPF record of permitted senders on smarthost.com - something that I have no control of.
Way out #2 - simple SSH tunnel
Set up a SSH tunnel from localhost:25 to smarthost.com:25 with port forwardingssh -L 25:smarthost.com:25 utumno@smarthost.comand point Sylpheed at localhost:25. That works, however:
- the tunnel is sitting idle for 99% of the time, which is a waste of resources
- it will sometimes timeout or otherwise collapse.
The following script can help with the second issue
#!/bin/bash
while [[ 1 ]];
ssh -N -L 25:smarthost.com:25 utumno@smarthost.com
sleep 5
done
Add this to your initscripts and the tunnel should work all the time. However, to take care of the first issue we really need to approach the problem from a different side.
Way out #3 - use inetd to manage the tunnel
Our ssh tunnel is essentially a service offered to email client software and occasionally this service needs to be restarted. Under Linux, the tool that handles these kinds of services is inetd, or xinetd. These are daemons that listen on a port and when a connection arrives at that port they start a server process to handle that connection.Before we tackle inetd however, let's take care of creating a special-purpose public/private key pair to be used by our tunnel. Type
ssh-keygen -t dsa -f ~/.ssh/tunnel_keyand enter an empty passphrase when prompted. This will create the files ~/.ssh/tunnel_key (your private key) and ~/.ssh/tunnel_key.pub (your public key). Leave the first file where it is. From the second file (~/.ssh/tunnel_key.pub )we will make a new special authorized key on our smarthost. It contains some text of the form
ssh-dss AAAAB3NzaC1kc3MAAAC.........Copy this text and on the smarthost add a line to the file ~/.ssh/authorized_keys2 :
utumno@smarthost:~/.ssh$ cat tunnel_key.pub >> authorized_keys2then edit this file and add command 'command="nc localhost 25", no-X11-forwarding, no-agent-forwarding, no-port-forwarding' in front if the 'ssh-dss' stanza so that the line looks like
command="nc localhost 25",no-X11-forwarding,no-agent-forwarding,no-port-forwarding ssh-dss AAAAB3NzaC1kc3MAAAC.........This makes ssh execute the command 'nc localhost 25' (25=SMTP port) whenever we ssh to the smarthost using the 'tunnel_key' key. This requires that the netcat (nc) program be installed on this machine, and be in the user's path.
Now you should be able to connect to smarthost' SMTP daemon with
utumno@laptop$ ssh -i ~/.ssh/tunnel_key utumno@smarthost.com 220 smarthost.com ESMTP Sendmail 8.13.8/8.13.4; Wed, 17 Jan 2007 11:31:55 +0100 (CET) QUIT 221 2.0.0 smarthost.com closing connection Connection to smarthost.com closed.The final step is to use inetd to listen on local port 25 and create the tunnel whenever something ( like our Sylpheed ) tries to connect to it. Add the following line to '/etc/inetd.conf' :
# ssh tunnel to smarthost.com's SMTP server 127.0.0.1:smtp stream tcp nowait root /usr/bin/ssh -q -T -i /root/.ssh/tunnel_key utumno@smarthost.comand reload inetd with
utumno@laptop$ /etc/init.d/openbsd-inetd reloadVoilla! Transparent SMTP relay via an SSH tunnel.
If you use xinetd ( which is by the way hard to do on Etch because of bug #403355 ) enter the following instead:
service smtp
{
socket_type = stream
protocol = tcp
wait = no
user = root
disable = no
server = /usr/bin/ssh
server_args = -q -T -i /root/.ssh/tunnel_key utumno@smarthost.com
groups = yes
bind = 127.0.0.1
}
References
Most of the info was shamelessly copied from here.Also, take a look at J. Franken's excellent SSH-tunneling HOWTO.
Yet another possibility are the mail-over-IMAP solutions offered e.g. by Courier and (I think Dovecot). These let you send your mail to /dev/null locally while your mailer stores a copy not in =sent, but in =to-be-sent. offlineimap then synchronises that with the server, where mail in =to-be-sent is periodically fed to sendmail and moved to =sent afterwards. This works quite well for me and has the added benefit that I don't produce any Received headers, no matter from where I send.
-madduck
[ Parent | Reply to this comment ]
Get an OpenVPN on the server, set up the client on your laptop/computer, and use an ssh tunnel to connect to the server.
Advantages:
* ssh tunnels carrying OpenVPN never dies: OpenVPN's ttl signals keep ssh connection open
* you don't have to adapt your ssh command line and restart ssh each time you add/remove additional ports
* you can even put your default route on OpenVPN tunnel, if (and only if) you are smart enough to know how to keep out the ssh from that tunnel
* you can do this over and NSTX link and avoid paying for hotspots :) but this's an other stroy
asd
[ Parent | Reply to this comment ]
Another very clean alternative to this is UUCP over SSH : secure, transparent and works both ways.UUCP over SSH howto
[ Parent | Reply to this comment ]
[ Send Message | View Utumno's Scratchpad | View Weblogs ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
ServerAliveInterval 60Here 60 sec - is the interval when your client pings the server so firewalls don't shut it down due to inactivity.
[ Parent | Reply to this comment ]
1.
This:
utumno@laptop$ /etc/init.d/openssh-inetd reload
should be:
utumno@laptop$ /etc/init.d/openbsd-inetd reload
2.
'command="nc localhost 25" ,no-X11-forwarding,no-agent-forwarding,no-port-forwarding' should be 'command="nc localhost 25",no-X11-forwarding,no-agent-forwarding,no-port-forwarding ' (the space must be removed)
3.
A style note: I don't use root on the other end, I use a dedicated account on both sides.
--
|/usr/games/fortune
[ Parent | Reply to this comment ]
[ Send Message | View Utumno's Scratchpad | View Weblogs ]
[ Parent | Reply to this comment ]
--
|/usr/games/fortune
[ Parent | Reply to this comment ]
And while we're at it: When using example ip-addresses, please use "192.0.2.0/24". http://www.rfc-editor.org/rfc/rfc3330.txt says:
192.0.2.0/24 - This block is assigned as "TEST-NET" for use in documentation and example code. It is often used in conjunction with domain names example.com or example.net in vendor and protocol documentation. Addresses within this block should not appear on the public Internet.
[ Parent | Reply to this comment ]
Please always use "example.com" or "example.org" in examples/MBL
[ Parent | Reply to this comment ]