Showing posts with label tunneling. Show all posts
Showing posts with label tunneling. Show all posts

Thursday, January 31, 2013

IPV6 in enterprise best practices/white papers

From time to time I look what's going on on a Nanog mailing list. It is a very interesting mailing list in which quite often something very interesting pops up. You don't have to sign to this mailing list in order to see posts, there are publicly available archives, which might be a better option for those sporadically looking at this list. This time my eye caught a thread with the subject line as in the title of this post. So, since IPv6 is hot topic these days, or at least it seems so, I decided to read through this thread and make summary along with pointers to materials that were linked to.

The thread was started on January 26th, 2013. by Pavel Dimow who asked for a real world example of IPv6 deployment in enterprise. More specifically, he said that he thinks that the procedure to introduce IPv6 is:
  1. Create address plan.
  2. Implement security on routers/switches and then hosts.
  3. Create AAAA and PTR records in DNS.
  4. Configure DCHPv6.
  5. Test IPv6 in LAN.
  6. Configure BGP with ISP.
He also wondered how to maintain PTR records in case SLAAC or DHCPv6 is used and should he use DDNS for that purpose. Finally, he asked weather to use SLAAC or DHCPv6.

The general consensus of repliers was that first IPv6 connectivity to the Internet should be established. The reason is that operating systems prefer IPv6 over IPv4 and if there is AAAA record, along with localy assigned IPv6 address, then IPv6 connection will be first established. Since, if you configure Internet connectivity as a last step, there is no path to destination, timeouts will have to expire in order to detect missing IPv6 connectivity and in the end users will experience delays. This scenario actually happened in one network I used. Namely, intranet Web server was given IPv6 address to test that IPv6 worked.  Since all operating systems today have IPv6 enabled by default clients on a local network tried to connect to Web server using IPv6 which wasn't possible since only a small part of intranet got IPv6 connectivity. Still, it turns out that it is possible to configure address preferences in an OS (though, I don't know which ones yet). And, there is a draft that defines how address preferences can be distributed via DHCPv6.

After obtaining addresses from ISP and making address plan the next step would be to configure network equipment, preferably not everything, something for testing. Very important is to get at least some experience with IPv6 before deploying it in a production environment. To get experience there are tunnel broker services that are free and very good. HE.net apparetnly also allows free IPv6 BGP connectivity via tunnels.

Here is more specific series of steps to introduce IPv6. This one was written by a person doing an actual deployment. Note that deployer had its own ASN:
  • get a /48 PI from the local LIR
  • configure the border routers to announce the prefix and do connectivity tests (ping Google/Facebook addresses using an IPv6 address from our own /48 - loopback on the router)
  • configure IPv6 addresses on internal router and do connectivity tests again
  • configure firewall interfaces with IPv6 addresses and again connectivity tests
  • configure IPv6 firewall rules (mostly a mirror of the IPv4 rulesets)
  • configure IPv6 address on DMZ servers (actually the first one configured were the DNS servers)
  • do connectivity tests again
  • publish IPv6 records for the DNS servers and for the domain and run ping/telnet 80 tests from another ipv6 enabled network to check that everything is OK.
  • publish AAAA records for all the hosts in the DMZ and making sure all the services available on IPv4 were also available on IPv6
  • did the same for the servers in the "Server network"
  • last step was to enable IPv6 on the network that served the users using RA with the stateful configuration bit set on the firewall and DHCPv6 to serve up DNS servers for IPv6
Security is very important aspect in any network, so it is in IPv6, too. Some of the IPv4 security mechanisms translate to IPv6 security, e.g. DHCP snooping, but there are some IPv6 specific things to be aware of, like RAs.

Scalability is other very important aspect of any network. There was subthread about snooping MLD, or lack of snooping. Namely, there are high density VM deployments in which even high end switches don't have enough processing/storage power. In that case, multicasting degrades to broadcasting. In one post a poster asked about some figures from real world switches, e.g. maximum number of multicast groups, but unfortunately, there was no answer.

Finally, very good source of different documentation about IPv6 deployment is Internet Society's Deploy360 pages. There are documents that describes how to develop address plan and Aaron Hughes presentation from NANOG.

Tuesday, November 22, 2011

SSH TAP tunnels: Using routing instead of bridging...

In the previous post about SSH tunneling, I used bridging functionality within Linux kernel in order to connect remote network with local laptop. But it is also possible to use routing in that case. The reason why you would prefer routing, instead of bridging, is the quantity of traffic that might be flowing from the remote network to your interface. And because you are probably connected with slower link than available bandwidth on the local network itself, that could be a real problem. So, routing could help in this case. Note that you are loosing ability to use some protocols, most notably those that use broadcasting since routing code won't route those packets.

The idea is to use routing in combination with proxy ARP. Basically, everything stays the same except you are not using bridging and you need to setup some basic forwarding features on remote host. So, here we go.

First add an explicit route for your remote host. That way it won't happen that you can not access it because the local network on which remote host is will be accessed in a special way:
ip route add remote_host via default_current_router
In case you don't know IP address of your default router (default_current_router) you can find it out using ip route sh command. And for remote_host you need to use IP address with network mask 32!

Now, log in to remote host using the usual ssh command that creates tap tunnel (for the meaning of parameters and what happens see previous post):
ssh -C -w any -o Tunnel=ethernet root@remotehost
After logging in, on local host add IP address from remote network that you are assigned when you directly connect on the remote network. In our example network this is the address 192.168.0.40/24 (see this previous post).

Now we have one interesting situation which I'm going to describe in some detail.

Start arping command on remote host like this (read this post about arping command):
arping -I tap0 192.168.0.40
Basically, you won't receive response. If you start tcpdump command, you'll notice that ARP requests are arriving, but there are no responses. The reason why there are no responses is because your local machine sees unexpected address in request and so ignores it.

You can turn on logging to see that those are really ignored with this command:
echo 1 > /proc/sys/net/ipv4/conf/tap0/log_martians
and now look into log file (/var/log/messages). You'll notice messages similar to the following ones:
Nov 22 14:37:25 w510 kernel: [147552.433215] martian source a.b.c.d from e.f.g.h, on dev tap0
Nov 22 14:37:25 w510 kernel: [147552.433221] ll header: ff:ff:ff:ff:ff:ff:16:90:4a:17:9d:d1:08:06
As you can see, it's called martian address. :)

Now, you can two options. The first one is to turn off filtering and the second one is to assign IP address to tap0 interface on remote host too. In general I don't suggest that you turn off rp filtering, but since in this case we are turning it off on a special (and restricted) interface I'll go that route, and also to save one IP address. So, on local machine do the following:
echo 1 > /proc/sys/net/ipv4/conf/tap0/rp_filtering
If you now try arping from local machine to remote machine, trying to reach IP address of remote machine, it won't work! You have to turn off rp filtering on remote machine too. So, execute the previous command there also.

One more thing for L2 part to fully work. When local machine asks from some address on local network, via tun0, remote host has to announce itself. For this purpose Proxy ARP is used but it has to be turned on. So, turn it on with the following command:
echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp
If you now try to "arping" any IP address, you'll aways get MAC address of tap0 on remote machine, and that's exactly what we wanted. But, you also need to do that because when machines on remote network search for you, then remote host has to announce himself and relay/forward everything over the tunnel to you.
echo 1 > /proc/sys/net/ipv4/conf/eth0/proxy_arp
I'm assuming that the interface name which attaches remote host to local network is named eth0, and I'm also assuming that you didn't create bridge device and attached eth0 to it (as it was described in the previous post).

Ok, time for L3 part. Everything has to be done on a remote machine. So, on a remote machine, first tell it that 192.168.0.40 is attached to tap0 interface:

ip route add 192.168.0.40/32 dev tap0
Next, allow IP forwarding:
echo 1 > /proc/sys/net/ipv4/ip_forward
And that's it. Only what's left is to automate the whole procedure.

Monday, November 14, 2011

SSH VPNs: Bridged connection to LAN using tap

In the previous post I showed how to create SSH tunnel that ends on a network  layer (i.e. ppp and point-to-point based vpns) and on a link layer (ethernet type). Now I'm continuing with a series of scenarios that do configuration on a network layer (and few on a link layer too).

This is the first scenario in which I want remote host to look like it is directly attached to a local network. The network layout for this scenario is shown in the following figure:

As you can see there is a local network that has address 192.168.0.0/24. On that local network there is a gateway (192.168.0.1) as well as remote server (192.168.0.30) that we are going to use as the end point of a tunnel. What we want to achieve is that our laptop, that is somewhere on the Internet and has IP address 10.2.4.60, behaves as if it is attached directly on a local network and to use IP address 192.168.0.40. This kind of setup when a single remote machine connects to some network remotely via VPN is offten called road-warrior scenario. To accomplish this we are going to use bridging built into the Linux kernel. In the future post I'll describe variant of this setup that uses forwarding (i.e. routing) to achieve the same thing.

Preparation steps

The idea (for this scenario) is to use briging. But since manipulating bridge and active interface might (and very probably will) disconnect you, it is better to first configure brigde with only a single interface, the one that connects remote computer to a local network. In case you are using CentOS (RHEL/Fedora or some derivative) then do the following on your remote server:
  1. Go into directory /etc/sysconfig/network-scripts.
  2. Copy file ifcfg-eth0 into ifcfg-br0 (I'm assuming that your active interface is eth0, if it is something else change the name accordingly). Also make a copy of that file in case you want to revert changes! Remove UUID line if there is any.
  3. Edit file ifcfg-eth0. Add line BRIDGE=br0, remove all lines that specify IP address and related parameters (broadcast, netmask, gateway, DNS, ...). Also be certain that BOOTPROTO parameter is set to none. Remove UUID line if there is any.
  4. Modify ifcfg-br0. Change type from Ethernet into Brige, also change name from eth0 into br0 and finally add line STP=off.
Now, restart machine and see if everything is OK. First, you should be able to connect to the machine, and second, there should be new interface, br0,  which has to have IP address of interface eth0. Interface eth0 itself should work (UP, LOWER_UP flags) and also it must not have IP address attached.

One other thing you have to take care of, firewall. In case you have firewall configured (which you should!), during this test it's best to disable it and enable it later. To disable firewall on CentOS/Fedora (and similar distributions) do the following:
service iptables stop
This will turn off firewall until you turn it on again, or until you restart machine. To turn it off permanently (strongly not advised!) do the following:
chkconfig iptables off
SELinux might get into your way. In case that you at some point receive the following error message:
channel 0: open failed: administratively prohibited: open failed
it's the indication that tap device hasn't been created because of missing privileges. The simplest way is to turn off temporarily SELinux (again, I do not advise to do that in production environment!):
setenforce 0
If, at any point, something doesn't work three things you can use to debug problems. The first one is option -v to ssh command (or -vv) that will make it verbose and it will print out what's happening. The next thing is to look into log files on the remote machine (for sshd messages). Finally, you should know how to use tcpdump tool.

Creating and configuring tunnel

Ok, for a start, open two terminals on a laptop and in each one of them switch to root user (su command). Then, in one of them execute ssh command like this:
ssh -w any -o Tunnel=ethernet remote_machine
This will connect you to the remote machine (after successful authentication) and create two tap devices, one on the local machine and the other on the remote machine. I'll assume that their name is tap0, on both sides. Now, switch temporarily to other terminal and execute the following command:
ip link set tap0 up
tcpdump -nni tap0
The first command will start interface and the second will run tcpdump command. You'll be able to see traffic from remote network as soon as we attach the other part of the tunnel to bridge br0. Options n instruct tcpdump not to print symbolic names of anything, while option i binds tcpdump to interface tap0. When you want to stop tcpdump, use Ctrl+C keys.

Now, on the remote host execute the following commands:
brctl addif br0 tap0
ip link set tap0 up
The first command will add tap device to bridge (more colloquially switch), and the second one will activate the interface. The moment you execute the other command you'll notice that tcpdump command, running in the second windows, starts to print some output. This output is the traffic from the local network, transferred to the laptop. Of course, you'll see traffic if there is any traffic on the local network.

One final step, to add IP address from the local network to laptop, i.e. 192.168.0.40. But before that, we have to add explicit route for remote host or otherwise things will lock up. The laptop will think that remote host is now directly attached, while it is not and nothing will work. So, execute the following command on laptop (terminate tcpdump or open new windows and switch to root):
ip route add 192.168.0.30/32 via your_default_route
Change the string your_default_route to your default router (check what it is using 'ip route sh' command, it is an IP address in the same line as the word default). Finally, we are ready to add IP address, also on laptop, in the terminal where you added explicit route, execute the following command:
ip addr add 192.168.0.40/24 dev tap0
From that moment on, when you communicate with any host on local network this communication will go through the tunnel to the remote host that will send traffic to the local network for you. Hosts on the network 192.168.0.0/24 won't notice that you are actually somewhere else on the Internet.

One final thing. The question which destinations you want to reach via this tunnel. You can select all, or only a subset of destinations. In any case, you use routing to achieve that, i.e. you use the following command:
ip route add destination via gateway_on_local_network
Change destination to whatever you want to access via tunnel. In case you want everything than use word default (it could happen that you first need to remove existing route for default!). Or, you can set network, or IP address. Let's suppose that you want to reach google via local network. In that case find out IP address (or network) fo google and use that instead of the word destionation.

In place of gateway_on_local_network use gateway on the local network. In our case that is 192.168.0.1.

Finally, to tear down connection, just kill ssh.

Automating access

As a last thing, I'll describe how to automate the whole procedure. If you want fully automated solution, then first you have to configure passwordless login for ssh. Then, create two scripts. The first one will be called vpn_start.sh, will be placed on remote machine in a directory /usr/local/sbin and will contain the following lines:
#!/bin/bash
ip link set tap0 up
brctl addif br0 tap0
Lets call the second script also vpn_start.sh and let it be placed in the /usr/local/sbin/ directory. The content of that script should be:
#!/bin/bash
ssh -f -w any -o Tunnel=ethernet remote_machine /usr/local/sbin/vpn_start.sh
ip route add 192.168.0.30/32 via your_default_route
ip addr add 192.168.0.40/24 dev tap0
ip route add destination via gateway_on_local_network
Repeat the last command as many times as necessary and change all the parameters accordingly. Don't forget to make both scripts executable! Now, to run the configuration just execute the script on the laptop:
/usr/local/sbin/vpn_start.sh
And that's it! Of course, those scripts might be a lot fancier, but this will do just good!

Friday, November 11, 2011

Tunneling everything with SSH... or how to make VPNs...

In the previous three posts I described how to use OpenSSH to tunnel traffic for different applications. What all those three techniques had in common was that they tunneled only TCP traffic and that every time the connection was initiated from the local machine, i.e. in a way it was not possible for the machine on the other side to transfer data to us (actually, it is possible to circumwent some of those restrictions, but more about those techniques in some other post!). Furthermore, the implicit assumption was that there is only one TCP connection from your host to remote host. In case there are multiple connections opened on different ports, you'll need to run ssh as many times as there are those connections.

In this post I'm going to describe how to tunnel all traffic, regardless of it's type, from one machine to some other. In a way, I'll show how to create VPN networks using SSH. Actually, there are three ways to do that:
  • Tunneling using ppp protocol on top of SSH
  • Tunneling using tun devices natively supported by newer versions of ssh on, at least, Linux.
  • Tunneling using Ethernet-like tap devices, also supported on a Linux OS.
In all of those cases you'll need to have administrative privileges in order to implement them. In the end, whichever path you decide to take (i.e. ppp or tun/tap) you'll end up configuring network parameters and firewall. So, I'm going to break down the description into more posts. The first post I'll deal with link layer setup (ppp/tun/tap) and the following posts I'll describe network layer configuration for different scenarios.

Link-layer setup

The basic goal of this step is to provide network device on which network layer will work.

Using ppp program and protocol

For this method there is a very good small howto document. Here I'll only repeat some relevant bits in case you don't want to read the whole document. First, you have to configure passwordless authentication to a remote host. This is easy to do and there are a plenty of references on the Internet. Later, maybe I write one, too. :) Anyway, in the following text I'll assume that you are using root account on both machines, i.e. you are root on a local machine and you are connecting to a remote machine under the username root. Beware that this is very bad security practice, but for a quick test or in a lab environment it'll do.

Ok, after you configured passwordless login for a root user, run the following command (note: this is a single line up to and including IP addresses) but it is broken into more lines because of a formatting in a browser!):
# pppd updetach noauth passive pty 'ssh REMOTE_HOST -o Batchmode=yes /usr/sbin/pppd nodetach notty noauth' 10.0.0.1:10.0.0.2
Using interface ppp0
Connect: ppp0 <--> /dev/pts/12
Deflate (15) compression enabled
local  IP address 10.0.0.1
remote IP address 10.0.0.2
#
As you can see, you got some information about interface and your prompt is immediately back. You need to have ppp package installed on both machines, if it is not then there will be an error message, something like command not found, and no connection will be established. Anyway, in this case everything was successful and we are notified that the remote side has address 10.0.0.2 and local side has address 10.0.0.1. To verify that everything works, try to ping remote side:
# ping -c 3 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=19.3 ms
64 bytes from 10.0.0.2: icmp_req=2 ttl=64 time=17.5 ms
64 bytes from 10.0.0.2: icmp_req=3 ttl=64 time=18.7 ms

--- 10.0.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 17.503/18.534/19.380/0.777 ms
If you see the output like the one above, that means that the link is working and the next thing to do is to setup network layer parameters (apart from IP addresses).

So, what happened? SSH created a communication channel between the two machines. This channel is then used by pppd processes on both ends to create ppp interfaces (one per each side). Then, this interface is used to transfer IP packets via protocol PPP. What we are (mis)using here is that pppd requires direct link between two points and through this link it then sends IP packets. Direct link is some sort of a serial interface, for example direct cable, UMTS/EDGE or similar connection, etc. The exact means by which two endpoints communicate is unimportant from pppd's perspective, what only matters is that whatever is sent on one end is received by other, and vice versa. So, because of this we could place SSH between two pppd processes.

The way the things are exectuted is as follows:
  1. Local pppd starts (the first pppd in a line), without authentication phase (option noauth), in a passive mode (option passive) meaning it is waiting for someone to connect. It also allocates one master/slave pty (option pty) pair in which he controls master side, while slave side is connected to ssh proces (argument to pty option). There are also two ip addresses at the end of the command line that are actually arguments to this instance of PPP. They instruct local ppp process to assign to itself address 10.0.0.1 and to the remote end 10.0.0.2 address.
  2. ssh process connects to REMOTE_HOST in batch mode (option -o BatchMode=yes). Basically batch mode tells ssh not to use password/passphrase because there is no user to enter necessary parameters. The rest of the command until closing single quote is the command that ssh has to execute after successfully connecting to remote host.
  3. ssh that connected to the remote machine runs there second pppd process. The options instruct that pppd process to use stdin/stdout instead of a termina (option notty), to not detach from the controlling terminal (option nodetach), and to not require authentication (option noauth).
And that's it. Quite simple as you can see. But as I said, it is not good security practice to allow root login from the network! Locally, you can run this command directly from the root account! So, for some production deployment you'll need to three two additional things:
  1. Create separate account that will be used to connect to a remote machine.
  2. Configure sudo so that it allows that new account to run pppd binary without entering the password.
  3. Modify invocation of ssh command so that remote user is specified and pppd program is executed via sudo command.
Using tun with Ethernet like functionality

For this mode you need to have the following directive in the server configuration (/etc/ssh/sshd_config):
Tunnel any
After the change don't forget to reload ssh configuration. What this configuration option tells ssh deamon is to allow tunneling using tun and tap devices. In other words, we can make our tunnel looks like ethernet interface, or like point-to-point interface on the 3rd (network) layer. Option any allows both. In case you want to restrict to a certain kind use either ethernet or point-to-point, depending on which one you need.

In this case we want Ethernet-like functionality, so assuming that you provided either any or ethernet parameter to Tunnel option, as a root user run ssh client as follows:
ssh -f -N -w any -o Tunnel=ethernet root@remotehost
change remotehost part with the host name (or IP address) you are connecting to. It is necessary to specify Tunnel option in ssh command because default value is point-to-point. The -w option requests from ssh to do tunneling using tap or tun device (depending on the value of Tunnel option) and in our case it is tap. After successfully logging to a remote machine, check interfaces with ip command (of ifconfig). You should see on both hosts that there is tap0 interface. If you already had tap interfaces, than the new ones will probably have highest number. Options -f and -N cause ssh to go into background after performing authentication, since command line is not necessary for tunneling.

To stop tap device, send a SIGTERM signal to ssh (using kill command, of course).

Using tun with only network layer functionality

As with the ethernet like functionality, you have to enable this mode in sshd configuration file, and also, you need to do this as a root on both sides of the connection.

The procedure to create point-to-point tunnels is similar to creating the Ethernet ones, only the argument is point-to-point instead of ethernet. Since point-to-point type is default, you don't have to specify Tunnel option, i.e.
ssh -f -N -w any root@remotehost
After logging into the remote host, ssh will go into background and you'll see new tun device created.

Tuesday, October 4, 2011

Yet more fun with SSH tunnels... accessing forbidden Web pages...

This is very interesting and simple hack, and analogous to SMTP one. or inverse version of Web access. Suppose that you want to access some Web site that is blocked by a firewall in your local network where you reside. In case you have some machine outside the local network (and of course, SSH isn't disabled) that you can access blocked Web site. I'll assume that the IP address of that outside machine is o.o.o.o. Furhtermore, suppose that the Web site in question is www.forbidden-web.com. Here is what you have to do:

Step 1. Find out which IP address this www.forbidden-web.com site has. You can use nslookup, host or dig commands for that, e.g.
$ nslookup www.forbidden-web.com
Server:        name_or_ip_address
Address:    some_ip_address_and_port

Name:    www.forbidden-web.com
Address: f.f.f.f
In this example, you are interested in the last line, i.e. IP address f.f.f.f.

Step 2. Edit your local /etc/hosts file and add the following line in it.
127.0.0.1      www.forbidden-web.com
Step 3. Create tunnel:
ssh -L 80:f.f.f.f:80 remoteuser@o.o.o.o
You have to be root in order to run that command. Furthermore, if the target site is accessed via https instead of http, change both number 80 into 443.

Step 4. Open Web browser and try to access forbidden Web site.

And that's it, you are done.

Of course there are some gotchas. For example, if the site you managed to access references some other forbidden site, then things won't fully work. Also, if it switches between protected (https) and unprotected (http) access you'll have problems using this simple method. Still, you can basically get around all those problems in many cases using variations of the previously given procedure.

More fun with ssh tunnels... accessing Web

Suppose that you have some Web application and you can access it only from local network, either because firewall on the host itself protects access or there is firewall at the network perimeter. Either way, you are currently somewhere on the Internet and you have to access this application, e.g. some administrative interface.

In my case, I have Zimbra Web administrative console access confined to local network only and sometimes it happens that I have to access it from remote location. Suppose that the remote site is zimbra.domain.com and that Zimbra Web administration interface is at default port 7071. I'll use z.z.z.z to denote IP address of that server. Additionally, you need to have some server within your local network that allows SSH access. This server has to be visible from the Internet, and if it is directly accessible that everything is fine. Otherwise, if you are using NAT you'll have to punch a hole in your firewall to forward all the connections from the outside to that machine. Either way, suppose that this server has public IP address s.s.s.s.

Ok, here is what you have to do. From your local machine, i.e. the one that you are currently work on and that is outside of you local network, execute the following ssh command:
ssh -L 7071:z.z.z.z:7071 s.s.s.s
All you have to do now is to open Web brower and enter the following URL:
https://127.0.0.1:7071
In case when virtual hosts are used, you'll have to add the following line into your /etc/hosts file:
127.0.0.1           web.server.name
and then, URL you'll use is:
https://web.server.name:7071
While this is necessary in general case, in case of Zimbra it is not since Zimbra should be only service running on a particular IP address.

Tuesday, September 20, 2011

OpenSSH and how to get around port 25 filters on local networks...

OpenSSH is a very capable tool and I'm using it for years. And even though I don't consider myself a beginner user, but rather an advanced one, every now and then I learn something new about this great tool. Here are two links to such sites that I found to be very interesting:
  1. SSH Can Do That? Productivity Tips for Working with Remote Servers
  2. 9 Awesome SSH Tricks
Be sure to also read comments there because they are useful too.

What I'm going to describe is how I'm using ssh tunneling capabilities to send email via remote server when local network blocks port 25 outside of the local network. Blocking port 25 is quite a frequent scenario, and useful security practice, to prevent, or at least lower the quantity of, outgoing spam from local network. Probably it was massively introduced during Slammer worm or somewhere around that time. Anyway, for an easier understanding here is a figure that tries to illustrate this particular scenario:

Network topology
In the given figure I'm using laptop computer and what I want to do is to send an email message using MY HOME MAIL SERVER as outgoing mail server. But, the exit router (or firewall) on LAN1 where I'm attached blocks any access to port 25 anywhere outside of the LAN1. In the same time, it allows outgoing ssh connections.

The general idea is to redirect mail client to connect to a localhost on port 25 and using ssh transfer this conection to remote mail host' local port 25. Note that, in order for this scenario to work you are not allowed to run local mail server, or, you have to redirect local mail client. The next premise is that the remote server allows ssh access. If it doesn't, then you have to find a host that allows. I'll deal with that scenario later, let us first go through this simpler scenario first.

To create tunnel that will transfer local connection to remote host run the following command as root user:

ssh -L 25:127.0.0.1:25 MY_HOME_MAIL_SERVER

What this command does is that it binds to a local port 25 (protocol tcp) and anything that connects to that address is forwarded to the other side where it connects to IP address 127.0.0.1 and port 25, i.e. to a local instance of mail server on MY HOME MAIL SERVER. You need to run this command as a root because of the local bind to privileged port (25).

One more thing you need to do is to trick your mail client to connect to localhost instead to MY_HOME_MAIL_SERVER. How to do this depends on how you configured your mail client. In case you entered symbolic name of MY_HOME_MAIL_SERVER into mail client then you can change it to 127.0.0.1, or better, change /etc/hosts and put there the following line:

127.0.0.1           MY_HOME_MAIL_SERVER

Don't forget to remove this line once you are finished. Otherwise, when you remove ssh tunnel you want be able to send mail any more!

Let me try to visualise what you did. Some time later I'll draw a figure, but now let me try with a words. With ssh you created a pipe that goes from the laptop to the MY_HOME_MAIL_SERVER. At the start of that pipe, on laptop, it is listening to port 25 at local addres. At the end, this pipe whatever comes, simply hands to the localhost and port 25, i.e. to a mail process running on the MY_HOME_MAIL_SERVER.

Finally, I what if you don't have ssh access to a MY_HOME_MAIL_SERVER? Well, in that case you have to find some computer to which you can ssh, and which can connect to port 25 of MY_HOME_MAIL_SERVER. Note that it can be any server on the Internet. To make things work now, you use almost the same ssh command, but with a little different arguments:

ssh -L 25:MY_HOME_MAIL_SERVER:25 YOUR_SSH_SERVER

Note that MY_HOME_MAIL_SERVER is IP adress or DNS name of your mail server, while YOUR_SSH_SERVER is IP address or DNS name of a server you use as a middle hop.

And that's it. :) Actually, very simple. But, personally I'm not satisfied with visualization so I'll improve it when I find more time and inspiration. :)

About Me

scientist, consultant, security specialist, networking guy, system administrator, philosopher ;)

Blog Archive