Linux Server Security (2nd Edition( [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Linux Server Security (2nd Edition( [Electronic resources] - نسخه متنی

Michael D. Bauer

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








4.3. Intermediate and Advanced SSH




Although most users use ssh and
scp for simple logins and file transfers,
respectively, this only scratches the surface of what SSH can do.
Next, we'll examine the following:


How RSA and DSA keys can be used
to make SSH transactions even more secure.


How null-passphrase keys
can allow SSH commands to be included in scripts.


How to cache SSH credentials in RAM to avoid unnecessary
authentication prompts.


How to tunnel
other TCP services through an encrypted SSH connection.




SSH and Perimeter Security




Secure Shell is obviously
the best way to administer all your servers from a single system,
especially if that system is an administrative workstation on your
internal network. But is it a good idea to allow external hosts
(e.g., administrators' personal/home systems) to
have SSH access, passing through your firewall to hosts in the DMZ or
even the internal network?


In my opinion, this is usually a bad idea. History has shown us that
Secure Shell (both commercial and free versions) is prone to the same
kinds of vulnerabilities as other applications: buffer-overflow
exploits, misconfiguration, and plain old bugs. Ironically, the same
flexibility and power that make SSH so useful also make a compromised
Secure Shell daemon a terrifying thing indeed.


Therefore, if you absolutely must have the ability to administer your
firewalled systems via untrusted networks, I recommend you use a
dedicated VPN tool such as FreeS/WAN to connect to an
access point in your DMZ or internal
networke.g., your administrative workstation. Run SSH on
that system to connect to the servers you need
to administer. An access point adds security even if you use SSH,
rather than a dedicated
VPN tool, to connect to it;
it's the difference between allowing inbound SSH to
all your servers or to a single system.


In either case, it should go without saying that your access point
must be well hardened and closely monitored.




4.3.1. Public-Key Cryptography




A
complete description of public-key cryptography (or
PK crypto) is
beyond the scope of this chapter. If you're
completely unfamiliar with PK crypto, I highly recommend the RSA
Crypto FAQ (available at http://www.rsasecurity/rsalabs/faq/)
or, even better, Bruce Schneier's excellent book,
Applied Cryptography (Wiley).


For our purposes, it's enough to say that in a
public-key scheme (illustrated in Figure 4-1), each
user has a pair of keys. Your private key is used to sign things
digitally and to decrypt things that have been sent to you. Your
public key is used by your correspondents to verify things that have
allegedly been signed by you and to encrypt data that they want only
you to be able to decrypt.



Figure 4-1. Public-key cryptography



Along the bottom of Figure 4-1, we see how two
users' key pairs are used to sign, encrypt, decrypt,
and verify a message sent from one to the other. Note that Bob and
Alice possess copies of each other's public keys,
but both keep their private key secret.


As we can see, the message's journey includes four
different key actions:


Bob signs a message using his private key.


Bob encrypts it using Alice's public key. (Aside
from the fact that Bob has probably kept a copy of the original
message, he cannot decrypt this messageonly Alice can!) Alice receives the message and decrypts it with her private key.


Alice uses Bob's public key to verify that it was
signed using his private key.


Compared to block ciphers such as
blowfish and
IDEA, in which the same
key is used both for encryption and decryption, this may seem
convoluted. Unlike block ciphers, though, for which secure key
exchange is problematic, PK crypto is easier to use securely.


This is because in PK schemes, two parties can send encrypted
messages to each other without first exchanging any secret data
whatsoever. There is one caveat: public-key algorithms are slower and
more CPU-intensive than other classes of cryptographic algorithms,
such as block ciphers and stream ciphers (e.g.,
3DES and
RC4, respectively). As
it happens, however, PK crypto can be used to generate keys securely
that can be used in other algorithms.


In practice, therefore, PK crypto is often used for authentication
("Are you really you?") and key
negotiation ("Which 3DES keys will we encrypt the
rest of this session with?"), but seldom for the
bulk encryption of entire sessions (data streams) or files. This is
the case with SSL, and it's also the case with SSH.



4.3.2. Advanced SSH Theory: How SSH Uses PK Crypto




As described in the beginning of the chapter ("How
SSH Works"), at the very beginning of each SSH
session, even before the end user is authenticated to the server, the
two computers use their respective host keys to negotiate a session
key. How the Diffie-Hellman Key Exchange Protocol works is both
beyond the scope of this discussion and complicated (for more
information, see the Internet Draft draft-ietf-secsh-
transport-07.txt, available at http://www.ietf.org). You need only know that
the result of this large-prime-number hoedown is a session key that
both parties know but that has not actually traversed the
as-yet-unencrypted connection.


This
session key is used to encrypt the data
fields of all subsequent packets via a block cipher agreed upon by
both hosts (transparently, but based on how each SSH process was
compiled and configured). Usually, one of the following is used:
Triple-DES (3DES), blowfish, or AES. Only after session encryption
begins can authentication take place.


This is a particularly interesting and useful characteristic of SSH:
since end-user authentication happens over an encrypted channel, the
authentication mechanism can be relatively weake.g., a
standard Unix username/password combination (which is inherently
weak, since its security depends on the secrecy of a single piece of
data: the username/password combination, which may not even be
difficult to guess).


As we've discussed, using such authentication with
SSH is exponentially more secure than, for example, Telnet, because
in SSH, both authentication credentials and actual session data are
protected. But SSH also supports much stronger authentication
methods.


Before we dive into
RSA/DSA
authentication, let's
return to key negotiation for a moment and ask: how can key
negotiation be transparent, given that it uses PK crypto and that
private keys are usually
passphrase
protected? SSH uses two different kinds of keypairs:
host keys and
user keys.


A host key is a special key pair that doesn't have a
passphrase associated with it. Since it can be used without anybody
needing to enter a passphrase first, SSH can negotiate keys and set
up encrypted sessions completely transparently to users. Part of the
SSH installation process is the generation of a host key (pair). The
host key generated at setup time can be used by that host
indefinitely, barring root compromise. And since
the host key identifies the host, not individual users, each host
needs only one host key. Note that host keys are used by all
computers that run SSH, regardless of whether they run only the SSH
client (ssh), SSH daemon
(sshd), or both.


A user key is a
key associated with an individual user and used to authenticate that
user to the hosts to which she initiates connections. Most user keys
must be unlocked with the correct passphrase before being used.


User keys provide a more secure authentication mechanism than
username/password authentication (even though all authentication
occurs over encrypted sessions). For this reason, SSH by default
always attempts PK authentication before falling back to
username/password. When you invoke SSH (via a local
ssh or scp command), this
is what happens:


SSH checks your $HOME/.ssh directory to see if
you have a private key (named id_dsa).


If you do, SSH will prompt you for the key's
passphrase and will then use the private key to create a signature,
which it will then send, along with a copy of your public key, to the
remote server.


The server will check to see if the public key is an allowed key
(i.e., belonging to a legitimate user and therefore present in the
applicable $HOME/.ssh/authorized_keys2 file).


If the key is allowed and identical to the server's
previously stored copy of it, the server will use it to verify that
the signature was created using this key's
corresponding private key.


If this succeeds, the server will allow the session to proceed.


If any of the previous actions fail and if the server allows it, the
server will prompt the user for username/password authentication.



The previous steps refer to the DSA authentication used in SSH
Protocol v2; RSA authentication is slightly more complicated but,
other than using different filenames, is functionally identical from
the user's perspective.




PK authentication is more secure than
username/password because a
digital signature cannot be reverse-engineered or otherwise
manipulated to derive the private key that generated it; neither can
a public key. By sending only digital signatures and
public keys over the network, we ensure
that even if the session key is somehow cracked, an eavesdropper
still won't be able to obtain enough information to
log on illicitly.



4.3.3. Setting Up and Using RSA and DSA Authentication




Okay,
we've established that PK authentication is more
secure than username/password, and you're ready to
enter the next level of SSH geekdom by creating yourself a user key
pair. Here's what you do.


First, on your client system (the machine you wish to use as a remote
console), you need to run ssh-keygen.
It calls for some choices; among other things, we can specify the
following:


Either RSA or DSA keys Key length An arbitrary "comment" field The name of the key files to be written The passphrase (if any) with which the private key will be encrypted
Now that RSA's patent has expired, choosing the
algorithm is somewhat arbitrary, at least from a legal standpoint.
But which algorithm we choose determines for which SSH protocol that
key can be used: SSH Protocol v1 uses RSA keys, and SSH Protocol v2
uses DSA keys. SSH Protocol v2 is obviously more current and is the
version that was submitted to the IETF for consideration as an
Internet Standard. Furthermore, recent SSH vulnerabilities have
tended to involve SSH Protocol v1.


RSA itself hasn't been the culprit; the protocol and
the ways it's been implemented in the protocol have.
This may simply be because v1 has been around longer and people have
had more time to "beat up" on it.
Either way, there's no reason to expect that even
after more scrutiny, v2 will prove to be less secure than v1. Also,
the various developers of SSH are focusing their energies on Protocol
v2. Therefore, my personal preference is to use SSH Protocol v1 only
when I don't have a choice (e.g., when connecting to
someone else's older SSH servers).


Anyhow, when running ssh-keygen, use the
-d flag to set DSA as the algorithm; otherwise,
RSA is the default.


Key length is a more important
parameter. Adi Shamir's
"Twinkle" paper describes a
theoretical but plausible computer capable of cracking RSA/DSA keys
of 512 bits or less via brute force (http://cryptome.org/twinkle.eps), so I highly
recommend you create 1024-bit keys. The default key length is, in
fact, 1024; you can use the -b flag followed by a
number to specify a different one.


The "comment" field is not used by
any SSH process; it's strictly for your own
convenience. I usually set it to my email address on the local
system. That way, if I encounter the key in
authorized_keys files on my other systems, I
know where it came from. To specify a comment, use the
-C flag.


The passphrase and filenames can, but needn't, be
provided in the command line (using -N and
-f, respectively). If either is missing,
you'll be prompted for it.


Example 4-3 gives a sample
ssh-keygen session.


Example 4-3. Sample ssh-keygen session for a 1024-bit DSA key



mbauer@homebox:~/.ssh > ssh-keygen -d -b 1024 -C mbauer@homebox.pinheads. com
Generating DSA parameter and key.
Enter file in which to save the key (/home/mbauer/.ssh/id_dsa):
Enter passphrase (empty for no passphrase): *************************
Enter same passphrase again: *************************
Your identification has been saved in /home/mbauer/.ssh/id_dsa.
Your public key has been saved in /home/mbauer/.ssh/id_dsa.pub.
The key fingerprint is:
95:a9:6f:20:f0:e8:43:36:f2:86:d0:1b:47:e4:00:6e mbauer@homebox.pinheads.com In Example 4-3, I'm creating a DSA
key pair with a key length of 1024 bits and a comment string of
"mbauer@homebox.pinheads.com." I
let ssh-keygen prompt me for the file in which
to save the key. This will be the name of the private key, and the
public key will be this name with .pub appended
to it.


In this example, I've accepted the default filename
of id_dsa (and therefore also id_
dsa.pub). I've also let
ssh-keygen prompt me for the passphrase. The
string of asterisks (*************************)
won't actually appear when you enter your
passphrase; I inserted those in the example to indicate that I typed
a long passphrase that was not echoed back on the screen.


By the way,
passphrases are
an "all or nothing" proposition:
your passphrase should either be empty (if you intend to use the new
key as a host key or for scripts that use SSH) or should be a long
string that includes some combination of upper- and lowercase
letters, digits, and punctuation. This isn't as hard
as it may sound. For example, a line from a song with deliberate but
unpredictable misspellings can be easy to remember but difficult to
guess. Remember, though, that the more random the passphrase, the
stronger it will be.


That's all that must be done on the client side. On
each remote machine you wish to access from this host, just add the
new public key to $HOME/.ssh/authorized_keys2
(where $HOME is the path of your home
directory). authorized_keys2 is a list of public
keys (one per very long line) that may be used for login by the user
in whose home directory authorized_keys2
resides.


To add your public key to a remote host on which you
have an account, simply transfer the file containing your public key
(id_dsa.pub in the previous example) to the
remote host and concatenate it to your
authorized_keys2 file. How you get the file
there doesn't matter a whole lot; remember,
it's your public key, so if it were to be copied by
an eavesdropper en route, there would be no need for concern. But if
you're paranoid about it, simply enter the
following:


scp ./id_dsa.pub remotehostname:/your/homedir (See the earlier section, Section 4.2.4.) Then to add it to
authorized_keys2, log on to the remote host and
enter the following:


cat id_dsa.pub >> .ssh/authorized_keys2 (assuming you're in your home directory).
That's it! Now whenever you log in to that remote
host using SSH, the session will look something like Example 4-4.


Example 4-4. ssh session with DSA authentication



mbauer@homebox:~/ > ssh -2 zippy.pinheads.com
Enter passphrase for DSA key '/home/mbauer/.ssh/id_dsa':
Last login: Wed Oct 4 10:14:34 2000 from homebox.pinheads.com
Have a lot of fun...
mbauer@zippy:~ > _ Notice that when I invoked ssh in Example 4-4, I used the -2 flag: this
instructs SSH to try SSH Protocol v2 only. By default Protocol v1 is
used, but v1 only supports RSA keys, and we just copied over a DSA
key. Note also that the key is referred to by its local filename:
this is a reminder that when we use RSA or DSA authentication, the
passphrase we enter is only used to
"unlock" our locally stored private
key and is not sent over the network in any form.


There's one last thing I should mention about Example 4-4. It makes two assumptions about the remote
server:


That I have the same username as I do locally.


That the remote server recognizes SSH Protocol v2.



If the first assumption isn't true, I need either to
use the -l flag to specify my username on the
remote host or, instead, to use scp-style
username@hostname syntaxe.g.,
mick@zippy.pinheads.com.


If Protocol v2 isn't supported by the remote
sshd daemon, I'll have to try
again without the -2 flag and let SSH fall back to
username/password authentication, unless I've got an
RSA key pair whose public key is registered on the remote machine.


To do all this with RSA keys, we follow pretty much the same steps
but with different filenames:


Create an RSA user-key pair with ssh-keygen, for
example:


ssh-keygen -b 1024 -C mbauer@homebox.pinheads.com On each remote host to which you wish to connect, copy your public
key onto its own line in the file
authorized_keys in your
$HOME/.ssh directory. (The default filenames for
RSA keys are identity and
identity.pub.) Again, if you run ssh without the
-2 flag, it will try RSA authentication by
default.


What happens if you forget your RSA or DSA key's
passphrase? How will you get back into the remote machine to change
the now unusable key's authorized_keys
file? Not to worry: if you attempt RSA or DSA authentication and fail
for any reason, SSH will revert to username/password authentication
and prompt you for your password on the remote system. If, as
administrator, you wish to disable this
"fallback" mechanism and maintain a
strict policy of RSA/DSA logins only, change the parameter
PasswordAuthentication to No in
sshd_config on each
remote host running sshd.


As long as we're talking about the server side of
the equation, note that by default, sshd allows
both RSA and DSA authentication when requested by an
ssh client process. The
sshd_config parameters used to allow or disallow
these explicitly are RSAAuthentication and
DSAAuthentication, respectively.

4.3.4. Minimizing Passphrase Typing with ssh-agent




Establishing one or more user keys improves authentication security
and harnesses more of SSH's power than
username/password authentication. It's also the
first step in using SSH in shell scripts. There's
just one small obstacle to automating the things
we've done with PK crypto: even though the
challenge-response authentication between client and server is
transparent, the process of locally unlocking one's
private key by entering a passphrase isn't. How can
we safely skip or streamline that process?


There are several ways. One is to use a
passphrase-less key, in which case SSH will
skip the passphrase prompt and immediately begin the transparent
challenge- response authentication to the server whenever the key is
used. (We'll talk more about passphrase-less keys in
a moment.) Another way is to use ssh-agent.


ssh-agent
is, essentially, a private-key cache in RAM that allows you to use
your private key repeatedly after entering its passphrase just once.
When you start ssh-agent and then load a key
into it with ssh-add, you are prompted for the
key's passphrase, after which the
"unlocked" private key is held in
memory in such a way that all subsequent invocations of
ssh and scp will be able to
use the cached, unlocked key without reprompting you for its
passphrase.


This might sound insecure, but it isn't necessarily.
First, only an ssh-agent
process's owner can use the keys loaded into it. For
example, if root and bubba
are both logged in and both have started their own
ssh-agent processes and loaded their respective
private keys into them, they cannot get at each
other's cached keys; there is no danger of
bubba using
root's credentials to run
scp or ssh processes.


Second, ssh-agent listens only to local
ssh and scp processes; it
is not directly accessible from the network. In other words, it is a
local service, not a network service per se. There is no danger,
therefore, of an outside would-be intruder hijacking or otherwise
compromising a remote ssh-agent process.


Using ssh-agent is fairly straightforward:
simply enter ssh-agent and execute the commands
it prints to the screen. This last bit may sound confusing, and
it's certainly counterintuitive. Before going to the
background, ssh-agent prints a brief series of
environment-variable declarations appropriate to whichever shell
you're using that must be made before you can add
any keys (see Example 4-5).


Example 4-5. Invoking ssh-agent



mbauer@pinheads:~ > ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-riGg3886/agent.3886; export SSH_AUTH_SOCK;
SSH_AGENT_PID=3887; export SSH_AGENT_PID;
echo Agent pid 3887;
mbauer@pinheads:~ > _ In Example 4-5, I'm one-third of
the way there: I've started an
ssh-agent process, and
ssh-agent has printed out the variables I need
to declare using BASH syntax.


All I need to do now is select everything after the first line in the
example and before the last line (as soon as I release the left mouse
button, this text will be copied) and right-click over the cursor on
the last line (which will paste the previously selected text into
that spot). I may need to hit Enter for that last echo to be
performed, but that echo isn't really necessary
anyhow.


Note that such a cut and paste will work in any xterm, but for it to
work at a tty (text) console, gpm will need to
be running. An alternative approach is to redirect
ssh-agent's output to a file,
make the file executable, and execute the file within your current
shell's context (Example 4-6).


Example 4-6. Another way to set ssh-agent's environment variables



mbauer@pinheads:~ > ssh-agent > temp
mbauer@pinheads:~ > chmod u+x temp
mbauer@pinheads:~ > . ./temp Once ssh-agent is running and
SSH_AUTH_SOCK and SSH_AGENT_PID
have been declared and exported, it's time to load
your private key. Simply type ssh-add, followed by
a space and the name (with full path) of the private key you wish to
load.


You can use ssh-add
as many times (to load as many keys) as you like. This is useful if
you have both an RSA and a DSA key pair and access different remote
hosts running different versions of SSH (i.e., some that support only
RSA keys and others that accept DSA keys).



4.3.5. Passphrase-Less Keys for Maximum Scriptability




ssh-agent is useful if you run scripts from a
logon session or if you need to run ssh and/or
scp repeatedly in a single session. But what
about cron jobs?
Obviously, cron can't perform
username/password or enter a passphrase for PK authentication.


This is the place to use a passphrase-less
key pair. Simply run ssh-keygen as described
earlier, but instead of entering a passphrase when prompted, press
Enter. You'll probably also want to enter a filename
other than identity or
id_dsa, unless the key pair is to be the default
user key for some sort of special account used for running automated
tasks.


To specify a particular key to use in either an
ssh or scp session, use the
-i flag. For example, if I'm
using scp in a cron job
that copies logfiles, my scp line might look
like this:


scp -i /etc/script_dsa_id /var/log/messages.* scriptboy@archive.g33kz.org:~ When the script runs, this line will run without requiring a
passphrase: if the passphrase is set to Enter, SSH is smart enough
not to bother prompting the user.


But remember, on the remote-host side I'll need to
make sure the key in /etc/script_ dsa_id.pub has
been added to the appropriate authorized_keys2
file on the remote host, e.g.,
/home/scriptboy/.ssh/authorized_keys2.



Always protect all private keys! If their permissions
aren't already
group=none,other=none, then enter the following:


chmod go-rwx private_key_filename




4.3.6. Using SSH to Execute Remote Commands




Now it's time to take a step back from all this PK
voodoo to discuss a simple feature of SSH that is especially important for
scripting: remote commands. So far we've been using
the command ssh strictly for remote shell
sessions. However, this is merely its default behavior; if we invoke
ssh with a command line as its last argument(s),
SSH will execute that command line rather than a shell on the remote
host.


For example, suppose I want to take a quick peek at my remote
system's log (see Example 4-7).


Example 4-7. Running cat on a remote host (if no passphrase is needed)



mbauer@homebox > ssh mbauer@zippy.pinheads.com cat /var/log/messages | more
Oct 5 16:00:01 zippy newsyslog[64]: logfile turned over
Oct 5 16:00:02 zippy syslogd: restart
Oct 5 16:00:21 zippy ipmon[29322]: 16:00:20.496063 ep0 @10:1 p 192.168.1.103,33247 -> 10.1.1.77,53 PR udp len 20 61 K-S K-F
etc.


In Example 4-7, the host zippy
will send back the contents of its
/var/log/messages file to my local console.
(Note that output has been piped to a local more
process.) Two caveats are in order here. First, running remote commands that
require subsequent user interaction is tricky and should be
avoidedwith the exception of shells, ssh
works best when triggering processes that don't
require user input. Also, all authentication rules still apply: if
you would normally be prompted for a password or passphrase, you
still will. Therefore, if using SSH from a cron
job or in other noninteractive contexts, make sure
you're either using a passphrase-less key or that
the key you are using is first loaded into
ssh-agent.


Before we leave the topic of SSH in scripts, I would be remiss if I
didn't mention rhosts and
shosts authentication. These are mechanisms by
which access is automatically granted to users connecting from any
host specified in any of the following files:
$HOME/.rhosts,
$HOME/.shosts,
/etc/hosts.equiv, and
/etc/shosts.equiv.


As you might imagine, rhosts access is wildly
insecure, since it relies solely on source IP addresses and
hostnames, both of which can be
spoofed
in various ways. Therefore, rhosts
authentication is disabled by default. shosts is
different: although it appears to behave the same as
rhosts, the connecting host's
identity is verified via host-key checking; furthermore, only
root on the connecting host may transparently
connect via the shosts mechanism.


By the way, combining
rhosts access with RSA or DSA
authentication is a good thing to do, especially when using
passphrase-less keys: while on its own the
rhosts mechanism isn't very
secure, it adds a small amount of security when used in combination
with other things. In the case of passphrase-less RSA/DSA
authentication, the rhosts mechanism makes it a
little harder to use a stolen key pair. See the
sshd(8) manpage for details on using
rhosts and shosts with SSH,
with or without PK authentication.

4.3.7. TCP Port Forwarding with SSH: VPN for the Masses!




And now we arrive at the payoff: port
forwarding. ssh gives us a mechanism for
executing remote logins/shells and other commands;
sftp and scp add file
copying. But what about X? POP3? LPD? Fear not, SSH can secure these
and most other TCP-based services!


Forwarding X applications back to your remote console is simple.
First, on the remote host, edit (or ask your admin to edit)
/etc/ssh/sshd_config and set
X11Forwarding
to yes (in OpenSSH Version 2x, the default is
no). Second, open an ssh
session using the authentication method of your choice from your
local console to the remote host. Third, run whatever X applications
you wish. That's it!


Needless to say (I hope), X must be running on your local system; if
it is, SSH will set your remote DISPLAY variable
to your local IP address, and the remote application will send all X
output to your local X desktop. If it doesn't, try
invoking your ssh client with the
-X flag; this flag is also necessary if
ForwardX11 isn't set to
yes in your client system's
/etc/ssh/ssh_config file.


Example 4-8 is a sample
X-forwarding session (assume the remote
host zippy allows X11 forwarding).


Example 4-8. Forwarding an xterm from a remote host



mick@homebox:~/ > ssh -2 -X mbauer@zippy.pinheads.com
Enter passphrase for DSA key '/home/mick/.ssh/id_dsa':
Last login: Wed Oct 4 10:14:34 2000 from homebox.pinheads.com
Have a lot of fun...
mbauer@zippy:~ > xterm & After the xterm & command is issued, a new
xterm window will open on the local desktop. I could just as easily
(and can still) run Netscape, GIMP, or anything else my local X
server can handle (provided the application works properly on the
remote host).


X is the only category of service that SSH is hardcoded to forward
automatically. Other services are easily forwarded using the
-L flag (note uppercase!). Consider the session
displayed in Example 4-9.


Example 4-9. Using ssh to forward a POP3 email session



mick@homebox:~/ > ssh -2 -f mbauer@zippy -L 7777:zippy:110 sleep 600
Enter passphrase for DSA key '/home/mick/.ssh/id_dsa':
mick@homebox:~/ > mutt The first part of the ssh line looks sort of
familiar: I'm using SSH Protocol v2 and logging on
with a different username (mbauer) on the remote
host (zippy) than locally
(mick@homebox). The -f flag
tells ssh to fork itself into the background
after starting the command specified by the last argumentin
this case, sleep 600. This means that the
ssh process will sleep for 10 minutes instead of
starting a shell session.


Ten minutes is plenty of time to fire up mutt
or some other POP3 client,
which brings us to the real magic: -L defines a
local forward, which redirects a local TCP port
on our client system to a remote port on the server system. Local
forwards follow the syntax
local_port_number:remote_hostname:remote_port_number,
where local_port_number is an arbitrary
port on your local (client) machine,
remote_hostname is the name or IP address
of the server (remote) machine, and
remote_port_number is the number of the
port on the remote machine to which you wish to forward connections.


Note that any users may use ssh to declare local
forwards on high ports ( >= 1024), but only
root may declare them on privileged ports ( <
1024). Returning to the previous example, after
ssh goes to sleep, we're
returned to our local shell prompt and have 10 minutes to send and
receive email with a POP3 client. Note that our POP3 software will
need to be configured to use
"localhost" as its POP3 server and
TCP 7777 as the POP3 connecting port.



What Are Ports and Why Forward Them?




TCP/IP
applications tell hosts apart via IP addresses: each computer
or device on a TCP/IP network has a unique IP address (e.g.,
192.168.3.30) that identifies it to other hosts and devices.


But what about different services running on the same host? How does
a computer receiving both WWW requests and FTP commands from the same
remote host tell the packets apart?


In TCP/IP networking, services are distinguished by
ports. Each
TCP or UDP packet has a source address and a destination address,
plus a source port and a destination port. Each service running on a
system "listens on" (looks for
packets addressed to) a different port, and each corresponding client
process sends its packets to that port. Ports are numbered 0 to
65,535.


Since there are two
TCP/IP
protocols that use ports, TCP and UDP, there are actually two sets of
65,535 ports each; that is, TCP 23 and UDP 23 are different ports.
Forget UDP for the moment, though: SSH forwards only TCP connections.
Destination ports, a.k.a.
listening ports, tend to be predictable (surfing
the Web would be very confusing if some web servers listened on TCP
80 but others listened on TCP 2219, still others on TCP 3212, etc.),
but source ports tend to be arbitrary.


Think of hosts as apartment buildings, where IP addresses are street
addresses and ports are apartment numbers. In each building, there
are a number of mail-order businesses in certain apartments. To order
something, you need to know both the street (IP) address and the
apartment (port) number and address your envelope accordingly.


Extending that analogy further, suppose that in this town, each type
of business tends to have the same apartment number, regardless of
which building it's located in. Thus, for any given
building, Apartment #TCP23 is always that building's
Telnet Pizza franchise, Apartment #TCP80 is always WWW Widgets, etc.
There's nothing to stop Telnet Pizza from renting
apartment #2020, but since everybody expects them to be in #TCP23,
that's where they usually set up shop.


(In contrast, nobody cares from which apartment number a given order
is mailed, as long it stays the same over a given
transaction's duration; you
wouldn't want to change apartments before that pizza
arrives.) There's even a secure courier service in apartment
#TCP22 in most buildings: SSH Corp. They accept mail only in
completely opaque envelopes delivered by armed guards. Best of all,
they'll deliver stuff to other businesses in their
building for you, but in a very sneaky way. Rather than mailing that
stuff to them directly, you put it in the mailbox for an
unoccupied apartment in your own building. From there, the
courier picks it up and delivers it first to his apartment in the
other building and then to the other business.


This is how an ssh client process (the courier)
listens for packets addressed to a local rather than a remote TCP
port and then forwards those packets over an SSH connection to the
sshd process (SSH Corp. office) on a remote host, which, in turn,
delivers the packets to a service listening on a different port
altogether (different business/apartment in the remote building).



After we execute the commands in Example 4-9,
mutt should connect to TCP port 7777 on the
local system (homebox), whereupon our local
ssh process will nab each POP3 packet, encrypt
it, and send it to the sshd process listening on
TCP port 22 on the remote host (zippy).
Zippy's sshd will decrypt each
packet and hand it off to the POP3 daemon (probably
inetd) listening on
zippy's TCP port 110, the
standard POP3 port. Reply packets, of course, will be sent backward
through the same stepsi.e., encrypted by the remote
sshd process, sent back to our local
ssh process, decrypted, and handed off to our
local mutt process.


After the 10-minute sleep process ends, the ssh
process will try to end, too; but if a POP3 transaction using the
local forward is still active, ssh will return a
message to that effect and remain alive until the forwarded
connection is closed. Alternately, we can open a login shell rather
than running a remote command such as sleep;
this will keep the session open until we exit the shell.
We'll just need to omit the -f
flag and use a different virtual console or window to start
mutt, etc. If we do use -f
and sleep, we aren't obliged to
sleep for exactly 600 seconds; the sleep interval is unimportant, as
long as it leaves us enough time to start the forwarded connection.


"Connection-oriented"
applications such as FTP and X only need enough time to begin, since
SSH won't close a session while
it's activei.e., while packets are traversing
it regularly.



In contrast, "connectionless"
applications such as POP3 and HTTP start and stop many brief
connections over the course of each transaction, rather than
maintaining one long connection; they don't have the
one-to-one relationship between transactions and TCP connections that
exists with connection-oriented services. Therefore,
you'll need to sleep SSH for long enough for
connectionless applications to do everything they need to do, rather
than just long enough to begin.




You can run any remote command that will achieve the desired pause,
but it makes sense to use sleep because
that's the sort of thing sleep
is for: it saves us the trouble of monopolizing a console with a
shell process and typing that extra exit
command. One more tip: if you use a given local forward every time
you use ssh, you can declare it in your very own
ssh configuration file in your home directory,
$HOME/.ssh/config. The syntax is similar to that
of the -L flag on the ssh
command line:


LocalForward 7777 zippy.pinheads.com:110 In other words, after the parameter name
LocalForward, you should have a space or tab, the
local port number, another space, the remote host's
name or IP address, a colon but no space, and the remote port number.
You can also use this parameter in
/etc/ssh/ssh_config if you wish it to apply to all
ssh processes run on the local machine. In
either case, you can define as many local forwards as you
neede.g., one for POP3, another on a different local port for
IRC, etc.



/ 94