个人工具

“UbuntuHelp:SSH VPN”的版本间的差异

来自Ubuntu中文

跳转至: 导航, 搜索
 
(未显示同一用户的5个中间版本)
第1行: 第1行:
{{From|https://help.ubuntu.com/community/SSH%20VPN}}
+
{{From|https://help.ubuntu.com/community/SSH_VPN}}
{{Languages|UbuntuHelp:SSH VPN}}
+
{{Languages|UbuntuHelp:SSH_VPN}}
 
This page details how to set up an SSH VPN.
 
This page details how to set up an SSH VPN.
NB: You MUST be using OpenSSH version 4.3 or better to do this-- this means that this will NOT work with Ubuntu 6.06 or less's default packages -- it will only work with the recently released Edgy, or with a locally compiled SSH version 4.3 or better.
+
NB: You must be using OpenSSH version 4.3 or later to do this-- this means that this will not work with Ubuntu 6.06 or earlier's default packages -- it will only work with Ubuntu 6.10 or later, or with a locally compiled SSH version 4.3 or later.
 +
This page discusses using SSH to set up SSH-based point to point connections, which can then be used to create routes that create virtual private networks.
 +
Note that using SSH in this fashion is not the "best" way to create a permanent, stable VPN. Notably, SSH uses TCP, and TCP over TCP can provide abysmal performance under pathological conditions. See also [http://openvpn.net/ OpenVPN], etc.
 
== Introduction ==
 
== Introduction ==
 
OpenSSH version 4.3 introduced a new feature: the ability to create on-the-fly "Virtual Private Networks" via the tunnel driver, or "tun" driver. This feature allows you to create a network interface that bridges two physically disparate network segments. A quick diagram:
 
OpenSSH version 4.3 introduced a new feature: the ability to create on-the-fly "Virtual Private Networks" via the tunnel driver, or "tun" driver. This feature allows you to create a network interface that bridges two physically disparate network segments. A quick diagram:
 
<pre><nowiki>
 
<pre><nowiki>
+---------------+            OpenSSH 4.3          +---------------+
+
    +---------------+            OpenSSH 4.3          +---------------+
|  Machine A  | tun0 -- Tunnel Interface -- tun0 |  Machine B  |
+
    |  Machine A  | tun0 -- Tunnel Interface -- tun0 |  Machine B  |
|  Has a tunnel | <------------------------------->|  Has a tunnel |   
+
    |  Has a tunnel | <------------------------------->|  Has a tunnel |   
|  and ethernet | 10.0.0.100            10.0.0.200 |  and ethernet |
+
    |  and ethernet | 10.0.0.100            10.0.0.200 |  and ethernet |
+-------+-------+    point to point connection    +-------+-------+
+
    +-------+-------+    point to point connection    +-------+-------+
eth0 |                creates a bridge                | eth0   
+
      eth0 |                creates a bridge                | eth0   
10.0.0.100 |              that plugs machine B              | 192.168.0.100
+
10.0.0.100 |              that plugs machine B              | 192.168.0.100
port 22  |                  into network A                  |           
+
  port 22  |                  into network A                  |           
forwarded |                                                  |
+
  forwarded |                                                  |
here    |                                                  |
+
    here    |                                                  |
+-------+-------+          +-~-~-~-~-~-~-~-+      +-------+-------+  
+
    +-------+-------+          +-~-~-~-~-~-~-~-+      +-------+-------+  
|  Network A  |          |              |      |  Network B  |
+
    |  Network A  |          |              |      |  Network B  |
|  10.0.0.1/24  | 1.2.3.4  |  The Internet |      | 192.168.0.1/24|
+
    |  10.0.0.1/24  | 1.2.3.4  |  The Internet |      | 192.168.0.1/24|
|  Has internet |<-------->|              |<----->|  Has internet |
+
    |  Has internet |<-------->|              |<----->|  Has internet |
|  NAT gateway  | Routable |              |      |  NAT gateway  |
+
    |  NAT gateway  | Routable |              |      |  NAT gateway  |
+---------------+ Address  +-~-~-~-~-~-~-~-+      +---------------+
+
    +---------------+ Address  +-~-~-~-~-~-~-~-+      +---------------+
 
</nowiki></pre>
 
</nowiki></pre>
 
What does this diagram represent? In this case, we have two machines, machine A and machine B. Machine A is connected to network A via ethernet, and machine B is connected to network B via ethernet. Machine A's IP address on Network A is 10.0.0.100, and Machine B's IP address on Network B is 192.168.0.100. Each network has an internet NAT gateway to allow for internet connectivity.
 
What does this diagram represent? In this case, we have two machines, machine A and machine B. Machine A is connected to network A via ethernet, and machine B is connected to network B via ethernet. Machine A's IP address on Network A is 10.0.0.100, and Machine B's IP address on Network B is 192.168.0.100. Each network has an internet NAT gateway to allow for internet connectivity.
 
In this example, we are connecting machine B to network A via an ssh tunnel interface. Machine A already has an IP addresses on network A: its ethernet interface address (10.0.0.100). Machine B must also be allocated one IP address on network A: its tunnel interface address (10.0.0.200).
 
In this example, we are connecting machine B to network A via an ssh tunnel interface. Machine A already has an IP addresses on network A: its ethernet interface address (10.0.0.100). Machine B must also be allocated one IP address on network A: its tunnel interface address (10.0.0.200).
Also, Machine B must have some access to the ssh server on Machine A; the most direct way for this to happen is that Machine A must have either a globally routable address itself; or (as is diagramed), port 22 (or whatever port ssh is running on) must be forwarded to Machine A by the NAT system. There are other ways to allow Machine B access to Machine A's ssh server, but I will leave these as an exercise for the reader.
+
Also, Machine B must have some access to the ssh server on Machine A; the most direct way for this to happen is that Machine A must have either a globally routable address itself; or (as is diagramed), port 22 (or whatever port ssh is running on) must be forwarded to Machine A by the NAT system. There are other ways to allow Machine B access to Machine A's ssh server, but this is left as an exercise for the reader.
 
Once the tunnel is set up, Machine B will be able to directly access Network A. In other words, Machine B would be "plugged in" to Network A via its tunnel with Machine A. Of couse, the devil's in the details: how do you set all this up?
 
Once the tunnel is set up, Machine B will be able to directly access Network A. In other words, Machine B would be "plugged in" to Network A via its tunnel with Machine A. Of couse, the devil's in the details: how do you set all this up?
== IP Forwarding ==
+
== IP forwarding ==
 
Of course the first and most obvious thing is that you'd better have IP forwarding enabled.
 
Of course the first and most obvious thing is that you'd better have IP forwarding enabled.
 
on Machine A (and it wouldn't hurt on B), execute:
 
on Machine A (and it wouldn't hurt on B), execute:
第33行: 第35行:
 
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
 
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
 
</nowiki></pre>
 
</nowiki></pre>
(sudo is the preferred way in Ubuntu to perform admin/root tasks)
+
== The SSH command ==
== The SSH Command ==
+
 
The actual SSH command that gets the ball rolling is quite simple:
 
The actual SSH command that gets the ball rolling is quite simple:
 
on Machine B, execute:
 
on Machine B, execute:
 
<pre><nowiki>
 
<pre><nowiki>
sudo ssh -w 0:0 1.2.3.4
+
sudo ssh -w 0:0 1.2.3.4
 
</nowiki></pre>
 
</nowiki></pre>
 +
Tip : Additional ssh options.
 +
<pre><nowiki>
 +
sudo ssh -NTCf -w 0:0 1.2.3.4
 +
</nowiki></pre>
 +
* -N Do not execute a remote command.  This is useful for just forwarding ports (or in this case tunnels).
 +
* -T Disable pseudo-tty allocation.
 +
* -C Requests compression of all data (including stdin, stdout, stderr, and data for forwarded X11 and TCP connections). Compress can speed up or potentially slow down your speed, so try with and without.
 +
* -f Requests ssh to go to background just before command execution.
 
This command creates a tunnel interface named tun0 on both the client and server systems. In keeping with our diagram above, the server is Machine A (with a globally routable IP address of 1.2.3.4), and the client is Machine B.
 
This command creates a tunnel interface named tun0 on both the client and server systems. In keeping with our diagram above, the server is Machine A (with a globally routable IP address of 1.2.3.4), and the client is Machine B.
Note that you will more than likely need to be root on both systems in order for ssh to be able to create these interfaces. Additionally, you will need the following settings in your sshd_config on Machine A (the server):
+
Note that you will need to have root access on both systems in order for ssh to be able to create these interfaces (see the security section below for security considerations and options to increase security). Additionally, you will need the following settings in your sshd_config on Machine A (the server):
 +
<pre><nowiki>
 +
PermitRootLogin yes
 +
PermitTunnel yes
 +
</nowiki></pre>
 +
-----
 +
'''''Security considerations'''''
 +
To increase security, use ssh keys - see [[UbuntuHelp:AdvancedOpenSSH|AdvancedOpenSSH]] for information on keys - and change `Permit Root Login yes` to :
 
<pre><nowiki>
 
<pre><nowiki>
PermitRootLogin yes
+
PermitRootLogin without-password
PermitTunnel yes
+
 
</nowiki></pre>
 
</nowiki></pre>
 +
Do not let that command fool you, `without-password` means root can not log in with a password (see man sshd).
 +
Also, on the server, if you use a key, you do NOT need to set a root password and your can restrict what commands can be run with the key (to ssh tunnels only).
 +
See the "Single-purpose keys" section of [http://pkeck.myweb.uga.edu/ssh/ this link] .
 +
On the client side, again if you do not wish to give your user complete root access , configure sudo. See [[UbuntuHelp:RootSudo|RootSudo]] or [http://manpages.ubuntu.com/manpages/jaunty/en/man5/sudoers.5.html sudoers man page].
 +
-----
 
If no errors occur, then you should be able to see a tun0 interface on both systems as existing, but unconfigured:
 
If no errors occur, then you should be able to see a tun0 interface on both systems as existing, but unconfigured:
 
Machine A:
 
Machine A:
 
<pre><nowiki>
 
<pre><nowiki>
% ifconfig tun0
+
% ifconfig tun0
tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
+
tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
POINTOPOINT NOARP MULTICAST  MTU:1500  Metric:1
+
          POINTOPOINT NOARP MULTICAST  MTU:1500  Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
+
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
+
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
+
          collisions:0 txqueuelen:500
RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)
+
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)
 
</nowiki></pre>
 
</nowiki></pre>
(% is your normal user account and not a character to type)
+
(% represents the shell prompt and not a character to type)
 
Machine B:
 
Machine B:
 
<pre><nowiki>
 
<pre><nowiki>
% ifconfig tun0
+
% ifconfig tun0
tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
+
tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
POINTOPOINT NOARP MULTICAST  MTU:1500  Metric:1
+
          POINTOPOINT NOARP MULTICAST  MTU:1500  Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
+
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
+
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
+
          collisions:0 txqueuelen:500
RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)
+
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)
 
</nowiki></pre>
 
</nowiki></pre>
== Configuring the Interfaces ==
+
== Configuring the interfaces ==
 
At this point, we've got interfaces, but they're unconfigured. All we need to do to configure them is give them each an IP address:
 
At this point, we've got interfaces, but they're unconfigured. All we need to do to configure them is give them each an IP address:
 
Machine A:
 
Machine A:
 
<pre><nowiki>
 
<pre><nowiki>
sudo ifconfig tun0 10.0.0.100 pointopoint 10.0.0.200
+
sudo ifconfig tun0 10.0.0.100 pointopoint 10.0.0.200
 
</nowiki></pre>
 
</nowiki></pre>
 
Machine B:
 
Machine B:
 
<pre><nowiki>
 
<pre><nowiki>
sudo ifconfig tun0 10.0.0.200 pointopoint 10.0.0.100
+
sudo ifconfig tun0 10.0.0.200 pointopoint 10.0.0.100
 
</nowiki></pre>
 
</nowiki></pre>
 
Once each interface is configured, we've essentially got the VPN set up; it's just minor details from here. In fact, we can now ping from Machine B to Machine A:
 
Once each interface is configured, we've essentially got the VPN set up; it's just minor details from here. In fact, we can now ping from Machine B to Machine A:
 
Machine B:
 
Machine B:
 
<pre><nowiki>
 
<pre><nowiki>
% ping 10.0.0.100
+
% ping 10.0.0.100
PING 10.0.0.100 (10.0.0.100) 56(84) bytes of data.
+
PING 10.0.0.100 (10.0.0.100) 56(84) bytes of data.
64 bytes from 10.0.0.100: icmp_seq=1 ttl=64 time=74.8 ms
+
64 bytes from 10.0.0.100: icmp_seq=1 ttl=64 time=74.8 ms
64 bytes from 10.0.0.100: icmp_seq=2 ttl=64 time=73.6 ms
+
64 bytes from 10.0.0.100: icmp_seq=2 ttl=64 time=73.6 ms
64 bytes from 10.0.0.100: icmp_seq=3 ttl=64 time=74.3 ms
+
64 bytes from 10.0.0.100: icmp_seq=3 ttl=64 time=74.3 ms
--- 10.0.0.100 ping statistics ---
+
 
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
+
--- 10.0.0.100 ping statistics ---
rtt min/avg/max/mdev = 73.649/74.278/74.880/0.549 ms
+
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
 +
rtt min/avg/max/mdev = 73.649/74.278/74.880/0.549 ms
 
</nowiki></pre>
 
</nowiki></pre>
 
And of course we can also ping from Machine A back to Machine B:
 
And of course we can also ping from Machine A back to Machine B:
 
Machine A:
 
Machine A:
 
<pre><nowiki>
 
<pre><nowiki>
% ping 10.0.0.200
+
% ping 10.0.0.200
PING 10.0.0.200 (10.0.0.200) 56(84) bytes of data.
+
PING 10.0.0.200 (10.0.0.200) 56(84) bytes of data.
64 bytes from 10.0.0.200: icmp_seq=1 ttl=64 time=75.2 ms
+
64 bytes from 10.0.0.200: icmp_seq=1 ttl=64 time=75.2 ms
64 bytes from 10.0.0.200: icmp_seq=2 ttl=64 time=74.0 ms
+
64 bytes from 10.0.0.200: icmp_seq=2 ttl=64 time=74.0 ms
64 bytes from 10.0.0.200: icmp_seq=3 ttl=64 time=74.0 ms
+
64 bytes from 10.0.0.200: icmp_seq=3 ttl=64 time=74.0 ms
--- 10.0.0.200 ping statistics ---
+
 
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
+
--- 10.0.0.200 ping statistics ---
rtt min/avg/max/mdev = 74.029/74.424/75.208/0.554 ms
+
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
 +
rtt min/avg/max/mdev = 74.029/74.424/75.208/0.554 ms
 
</nowiki></pre>
 
</nowiki></pre>
== Plugging Into the Network ==
+
== Plugging into the network ==
 
At this point, we've created the actual link that allows Machine B to be plugged into Network A, but we haven't set up any routing information to actually get packets back and forth between Machine B and Network A. The first thing we need to do is to tell Machine B about Network A:
 
At this point, we've created the actual link that allows Machine B to be plugged into Network A, but we haven't set up any routing information to actually get packets back and forth between Machine B and Network A. The first thing we need to do is to tell Machine B about Network A:
 
Machine B:
 
Machine B:
 
<pre><nowiki>
 
<pre><nowiki>
sudo route add -net 10.0.0.0 netmask 255.255.255.0 gw 10.0.0.200 tun0
+
sudo route add -net 10.0.0.0 netmask 255.255.255.0 gw 10.0.0.200 tun0
 
</nowiki></pre>
 
</nowiki></pre>
 
This allows us to send packets from Machine B to any IP address on Network A, via Machine A. However, to ensure that packets have a route back to Machine B, we need to set some things up on Machine A.
 
This allows us to send packets from Machine B to any IP address on Network A, via Machine A. However, to ensure that packets have a route back to Machine B, we need to set some things up on Machine A.
 
Machine A:
 
Machine A:
 
<pre><nowiki>
 
<pre><nowiki>
sudo arp -sD 10.0.0.200 eth0 pub
+
sudo arp -sD 10.0.0.200 eth0 pub
 
</nowiki></pre>
 
</nowiki></pre>
 
This ensures that other machines plugged into Network A will know to send packets destined for 10.0.0.200 to Machine A (so that it can forward them back to Machine B).
 
This ensures that other machines plugged into Network A will know to send packets destined for 10.0.0.200 to Machine A (so that it can forward them back to Machine B).
第117行: 第139行:
 
Machine B:
 
Machine B:
 
<pre><nowiki>
 
<pre><nowiki>
% ping 10.0.0.123
+
% ping 10.0.0.123
PING 10.0.0.123 (10.0.0.123) 56(84) bytes of data.
+
PING 10.0.0.123 (10.0.0.123) 56(84) bytes of data.
64 bytes from 10.0.0.123: icmp_seq=1 ttl=127 time=74.3 ms
+
64 bytes from 10.0.0.123: icmp_seq=1 ttl=127 time=74.3 ms
64 bytes from 10.0.0.123: icmp_seq=2 ttl=127 time=74.3 ms
+
64 bytes from 10.0.0.123: icmp_seq=2 ttl=127 time=74.3 ms
64 bytes from 10.0.0.123: icmp_seq=3 ttl=127 time=74.5 ms
+
64 bytes from 10.0.0.123: icmp_seq=3 ttl=127 time=74.5 ms
--- 10.0.0.123 ping statistics ---
+
 
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
+
--- 10.0.0.123 ping statistics ---
rtt min/avg/max/mdev = 74.307/74.416/74.577/0.335 ms
+
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
 +
rtt min/avg/max/mdev = 74.307/74.416/74.577/0.335 ms
 
</nowiki></pre>
 
</nowiki></pre>
 
== Expanding the scope of the VPN ==
 
== Expanding the scope of the VPN ==
第133行: 第156行:
 
Machine B:
 
Machine B:
 
<pre><nowiki>
 
<pre><nowiki>
sudo route add 1.2.3.4 gw 192.168.0.1 eth0
+
sudo route add 1.2.3.4 gw 192.168.0.1 eth0
 
</nowiki></pre>
 
</nowiki></pre>
 
In this case, 192.168.0.1 is Machine B's current default gateway; it is the gateway on Network B that provides internet connectivity. Before we switch Machine B's default gateway away from Network B, we must set up this explicit route so that tunnel packets will continue to flow.
 
In this case, 192.168.0.1 is Machine B's current default gateway; it is the gateway on Network B that provides internet connectivity. Before we switch Machine B's default gateway away from Network B, we must set up this explicit route so that tunnel packets will continue to flow.
第139行: 第162行:
 
Machine B:
 
Machine B:
 
<pre><nowiki>
 
<pre><nowiki>
sudo route add default gw 10.0.0.1 tun0
+
sudo route add default gw 10.0.0.1 tun0
sudo route del default gw 192.168.0.1 eth0
+
sudo route del default gw 192.168.0.1 eth0
 
</nowiki></pre>
 
</nowiki></pre>
 
In this case, again, 192.168.0.1 is Network B's default gateway, and 10.0.0.1 is Network A's default gateway. Since Machine B is now connected to Network A, we are telling it to use Network A's default gateway instead of its usual default gateway on Network B. At this point, the conversion is complete, and Machine B is now completely on Network A and has all the resources available to Network A, through the SSH tunnel. We can verify this by looking at the output of a tracepath:
 
In this case, again, 192.168.0.1 is Network B's default gateway, and 10.0.0.1 is Network A's default gateway. Since Machine B is now connected to Network A, we are telling it to use Network A's default gateway instead of its usual default gateway on Network B. At this point, the conversion is complete, and Machine B is now completely on Network A and has all the resources available to Network A, through the SSH tunnel. We can verify this by looking at the output of a tracepath:
 
Machine B:
 
Machine B:
 
<pre><nowiki>
 
<pre><nowiki>
% tracepath example.com
+
% tracepath example.com
1:  10.0.0.200 (10.0.0.200)                                0.291ms pmtu 1500
+
1:  10.0.0.200 (10.0.0.200)                                0.291ms pmtu 1500
1:  10.0.0.100 (10.0.0.100)                              168.589ms
+
1:  10.0.0.100 (10.0.0.100)                              168.589ms
2:  10.0.0.1 (10.0.0.1)                                  asymm  3  87.542ms
+
2:  10.0.0.1 (10.0.0.1)                                  asymm  3  87.542ms
3:  1.2.3.4 (1.2.3.4)                                    157.360ms
+
3:  1.2.3.4 (1.2.3.4)                                    157.360ms
 
</nowiki></pre>
 
</nowiki></pre>
 
== Automating it all with ifup/down ==
 
== Automating it all with ifup/down ==
第155行: 第178行:
 
Machine A:
 
Machine A:
 
<pre><nowiki>
 
<pre><nowiki>
iface tun0 inet static
+
iface tun0 inet static
pre-up sleep 5
+
        pre-up sleep 5
address 10.0.0.100
+
        address 10.0.0.100
pointopoint 10.0.0.200
+
        pointopoint 10.0.0.200
netmask 255.255.255.0
+
        netmask 255.255.255.0
up arp -sD 10.0.0.200 eth0 pub
+
        up arp -sD 10.0.0.200 eth0 pub
 
</nowiki></pre>
 
</nowiki></pre>
 
Machine B:
 
Machine B:
 
<pre><nowiki>
 
<pre><nowiki>
iface tun0 inet static
+
iface tun0 inet static
pre-up ssh -f -w 0:0 1.2.3.4 'ifdown tun0; ifup tun0'
+
        pre-up ssh -f -w 0:0 1.2.3.4 'ifdown tun0; ifup tun0'
pre-up sleep 5
+
        pre-up sleep 5
address 10.0.0.200
+
        address 10.0.0.200
pointopoint 10.0.0.100
+
        pointopoint 10.0.0.100
netmask 255.255.255.0
+
        netmask 255.255.255.0
up route add -net 10.0.0.0 netmask 255.255.255.0 gw 10.0.0.200 tun0
+
        up route add -net 10.0.0.0 netmask 255.255.255.0 gw 10.0.0.200 tun0
up route add 1.2.3.4 gw 192.168.0.1 eth0
+
        up route add 1.2.3.4 gw 192.168.0.1 eth0
up route add default gw 10.0.0.1 tun0
+
        up route add default gw 10.0.0.1 tun0
up route del default gw 192.168.0.1 eth0
+
        up route del default gw 192.168.0.1 eth0
down route add default gw 192.168.0.1 eth0
+
        down route add default gw 192.168.0.1 eth0
down route del default gw 10.0.0.1 tun0
+
        down route del default gw 10.0.0.1 tun0
down route del -net 10.0.0.0 netmask 255.255.255.0 gw 10.0.0.200 tun0
+
        down route del -net 10.0.0.0 netmask 255.255.255.0 gw 10.0.0.200 tun0
down route del 1.2.3.4 gw 192.168.0.1 eth0
+
        down route del 1.2.3.4 gw 192.168.0.1 eth0
 
</nowiki></pre>
 
</nowiki></pre>
 
These example /etc/network/interface snippets show how you would, on Machine B, simply have to execute:
 
These example /etc/network/interface snippets show how you would, on Machine B, simply have to execute:
 
Machine B:
 
Machine B:
 
<pre><nowiki>
 
<pre><nowiki>
sudo ifup tun0
+
sudo ifup tun0
 
</nowiki></pre>
 
</nowiki></pre>
 
And the system would automatically make the ssh connection, set up the tunnel, and turn on the VPN. Additionally, the ifdown command can be used to put the routes back to normal, or turn off the VPN.
 
And the system would automatically make the ssh connection, set up the tunnel, and turn on the VPN. Additionally, the ifdown command can be used to put the routes back to normal, or turn off the VPN.
第189行: 第212行:
 
There are many other possible ways to use SSH 4.3's tunnels besides creating a VPN to connect machine B to network A. For example, you could connect machine B to network A, and then route back on machine A to network B, creating a sort-of reverse VPN. Or you could connect machine B to network A, and then redirect traffic from network A to machine B to another system on network B. The possibilities are only limited by the amount of root access you have.
 
There are many other possible ways to use SSH 4.3's tunnels besides creating a VPN to connect machine B to network A. For example, you could connect machine B to network A, and then route back on machine A to network B, creating a sort-of reverse VPN. Or you could connect machine B to network A, and then redirect traffic from network A to machine B to another system on network B. The possibilities are only limited by the amount of root access you have.
 
----
 
----
[[category:CategoryDocumentation]]
 
  
 
[[category:UbuntuHelp]]
 
[[category:UbuntuHelp]]

2010年5月20日 (四) 00:17的最新版本

This page details how to set up an SSH VPN. NB: You must be using OpenSSH version 4.3 or later to do this-- this means that this will not work with Ubuntu 6.06 or earlier's default packages -- it will only work with Ubuntu 6.10 or later, or with a locally compiled SSH version 4.3 or later. This page discusses using SSH to set up SSH-based point to point connections, which can then be used to create routes that create virtual private networks. Note that using SSH in this fashion is not the "best" way to create a permanent, stable VPN. Notably, SSH uses TCP, and TCP over TCP can provide abysmal performance under pathological conditions. See also OpenVPN, etc.

Introduction

OpenSSH version 4.3 introduced a new feature: the ability to create on-the-fly "Virtual Private Networks" via the tunnel driver, or "tun" driver. This feature allows you to create a network interface that bridges two physically disparate network segments. A quick diagram:

    +---------------+            OpenSSH 4.3           +---------------+
    |   Machine A   | tun0 -- Tunnel Interface -- tun0 |   Machine B   |
    |  Has a tunnel | <------------------------------->|  Has a tunnel |  
    |  and ethernet | 10.0.0.100            10.0.0.200 |  and ethernet |
    +-------+-------+     point to point connection    +-------+-------+
       eth0 |                 creates a bridge                 | eth0  
 10.0.0.100 |               that plugs machine B               | 192.168.0.100
   port 22  |                  into network A                  |          
  forwarded |                                                  |
    here    |                                                  |
    +-------+-------+          +-~-~-~-~-~-~-~-+       +-------+-------+ 
    |   Network A   |          |               |       |   Network B   |
    |  10.0.0.1/24  | 1.2.3.4  |  The Internet |       | 192.168.0.1/24|
    |  Has internet |<-------->|               |<----->|  Has internet |
    |  NAT gateway  | Routable |               |       |  NAT gateway  |
    +---------------+ Address  +-~-~-~-~-~-~-~-+       +---------------+

What does this diagram represent? In this case, we have two machines, machine A and machine B. Machine A is connected to network A via ethernet, and machine B is connected to network B via ethernet. Machine A's IP address on Network A is 10.0.0.100, and Machine B's IP address on Network B is 192.168.0.100. Each network has an internet NAT gateway to allow for internet connectivity. In this example, we are connecting machine B to network A via an ssh tunnel interface. Machine A already has an IP addresses on network A: its ethernet interface address (10.0.0.100). Machine B must also be allocated one IP address on network A: its tunnel interface address (10.0.0.200). Also, Machine B must have some access to the ssh server on Machine A; the most direct way for this to happen is that Machine A must have either a globally routable address itself; or (as is diagramed), port 22 (or whatever port ssh is running on) must be forwarded to Machine A by the NAT system. There are other ways to allow Machine B access to Machine A's ssh server, but this is left as an exercise for the reader. Once the tunnel is set up, Machine B will be able to directly access Network A. In other words, Machine B would be "plugged in" to Network A via its tunnel with Machine A. Of couse, the devil's in the details: how do you set all this up?

IP forwarding

Of course the first and most obvious thing is that you'd better have IP forwarding enabled. on Machine A (and it wouldn't hurt on B), execute:

echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

The SSH command

The actual SSH command that gets the ball rolling is quite simple: on Machine B, execute:

 sudo ssh -w 0:0 1.2.3.4

Tip : Additional ssh options.

sudo ssh -NTCf -w 0:0 1.2.3.4
  • -N Do not execute a remote command. This is useful for just forwarding ports (or in this case tunnels).
  • -T Disable pseudo-tty allocation.
  • -C Requests compression of all data (including stdin, stdout, stderr, and data for forwarded X11 and TCP connections). Compress can speed up or potentially slow down your speed, so try with and without.
  • -f Requests ssh to go to background just before command execution.

This command creates a tunnel interface named tun0 on both the client and server systems. In keeping with our diagram above, the server is Machine A (with a globally routable IP address of 1.2.3.4), and the client is Machine B. Note that you will need to have root access on both systems in order for ssh to be able to create these interfaces (see the security section below for security considerations and options to increase security). Additionally, you will need the following settings in your sshd_config on Machine A (the server):

 PermitRootLogin yes
 PermitTunnel yes

Security considerations To increase security, use ssh keys - see AdvancedOpenSSH for information on keys - and change `Permit Root Login yes` to :

PermitRootLogin without-password

Do not let that command fool you, `without-password` means root can not log in with a password (see man sshd). Also, on the server, if you use a key, you do NOT need to set a root password and your can restrict what commands can be run with the key (to ssh tunnels only). See the "Single-purpose keys" section of this link . On the client side, again if you do not wish to give your user complete root access , configure sudo. See RootSudo or sudoers man page.


If no errors occur, then you should be able to see a tun0 interface on both systems as existing, but unconfigured: Machine A:

 % ifconfig tun0
 tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
           POINTOPOINT NOARP MULTICAST  MTU:1500  Metric:1
           RX packets:0 errors:0 dropped:0 overruns:0 frame:0
           TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
           collisions:0 txqueuelen:500
           RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

(% represents the shell prompt and not a character to type) Machine B:

 % ifconfig tun0
 tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
           POINTOPOINT NOARP MULTICAST  MTU:1500  Metric:1
           RX packets:0 errors:0 dropped:0 overruns:0 frame:0
           TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
           collisions:0 txqueuelen:500
           RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

Configuring the interfaces

At this point, we've got interfaces, but they're unconfigured. All we need to do to configure them is give them each an IP address: Machine A:

 sudo ifconfig tun0 10.0.0.100 pointopoint 10.0.0.200

Machine B:

 sudo ifconfig tun0 10.0.0.200 pointopoint 10.0.0.100

Once each interface is configured, we've essentially got the VPN set up; it's just minor details from here. In fact, we can now ping from Machine B to Machine A: Machine B:

 % ping 10.0.0.100
 PING 10.0.0.100 (10.0.0.100) 56(84) bytes of data.
 64 bytes from 10.0.0.100: icmp_seq=1 ttl=64 time=74.8 ms
 64 bytes from 10.0.0.100: icmp_seq=2 ttl=64 time=73.6 ms
 64 bytes from 10.0.0.100: icmp_seq=3 ttl=64 time=74.3 ms

 --- 10.0.0.100 ping statistics ---
 3 packets transmitted, 3 received, 0% packet loss, time 2001ms
 rtt min/avg/max/mdev = 73.649/74.278/74.880/0.549 ms

And of course we can also ping from Machine A back to Machine B: Machine A:

 % ping 10.0.0.200
 PING 10.0.0.200 (10.0.0.200) 56(84) bytes of data.
 64 bytes from 10.0.0.200: icmp_seq=1 ttl=64 time=75.2 ms
 64 bytes from 10.0.0.200: icmp_seq=2 ttl=64 time=74.0 ms
 64 bytes from 10.0.0.200: icmp_seq=3 ttl=64 time=74.0 ms

 --- 10.0.0.200 ping statistics ---
 3 packets transmitted, 3 received, 0% packet loss, time 2002ms
 rtt min/avg/max/mdev = 74.029/74.424/75.208/0.554 ms

Plugging into the network

At this point, we've created the actual link that allows Machine B to be plugged into Network A, but we haven't set up any routing information to actually get packets back and forth between Machine B and Network A. The first thing we need to do is to tell Machine B about Network A: Machine B:

 sudo route add -net 10.0.0.0 netmask 255.255.255.0 gw 10.0.0.200 tun0

This allows us to send packets from Machine B to any IP address on Network A, via Machine A. However, to ensure that packets have a route back to Machine B, we need to set some things up on Machine A. Machine A:

 sudo arp -sD 10.0.0.200 eth0 pub

This ensures that other machines plugged into Network A will know to send packets destined for 10.0.0.200 to Machine A (so that it can forward them back to Machine B). At this point, we do have two way communication betweek Network A and Machine B. Therefore, we can ping another machine on Network A from Machine B: Machine B:

 % ping 10.0.0.123
 PING 10.0.0.123 (10.0.0.123) 56(84) bytes of data.
 64 bytes from 10.0.0.123: icmp_seq=1 ttl=127 time=74.3 ms
 64 bytes from 10.0.0.123: icmp_seq=2 ttl=127 time=74.3 ms
 64 bytes from 10.0.0.123: icmp_seq=3 ttl=127 time=74.5 ms

 --- 10.0.0.123 ping statistics ---
 3 packets transmitted, 3 received, 0% packet loss, time 2001ms
 rtt min/avg/max/mdev = 74.307/74.416/74.577/0.335 ms

Expanding the scope of the VPN

At this point, we have successfully plugged Machine B into Network A, and Machine B can access Network A's resources and vice versa. However, what if we want to expand the scope of this VPN-- what if we want to pretend that Machine B's only network connection is through network A? If we did this, then all packets coming from or going to Machine B would route through Network A; this would complete Machine B's integration into the private network. So, how do we do this? Simple: we just switch Machine B's default gateway. However, first, we must create a host-based route to Machine A's globally routable IP address; all packets except for the packets that actually create the link must go through the tunnel, but of course the packets that create the tunnel cannot go through the tunnel. Machine B:

 sudo route add 1.2.3.4 gw 192.168.0.1 eth0

In this case, 192.168.0.1 is Machine B's current default gateway; it is the gateway on Network B that provides internet connectivity. Before we switch Machine B's default gateway away from Network B, we must set up this explicit route so that tunnel packets will continue to flow. After that route is in place, we can switch Machine B's default gateway: Machine B:

 sudo route add default gw 10.0.0.1 tun0
 sudo route del default gw 192.168.0.1 eth0

In this case, again, 192.168.0.1 is Network B's default gateway, and 10.0.0.1 is Network A's default gateway. Since Machine B is now connected to Network A, we are telling it to use Network A's default gateway instead of its usual default gateway on Network B. At this point, the conversion is complete, and Machine B is now completely on Network A and has all the resources available to Network A, through the SSH tunnel. We can verify this by looking at the output of a tracepath: Machine B:

 % tracepath example.com
 1:  10.0.0.200 (10.0.0.200)                                0.291ms pmtu 1500
 1:  10.0.0.100 (10.0.0.100)                              168.589ms
 2:  10.0.0.1 (10.0.0.1)                                  asymm  3  87.542ms
 3:  1.2.3.4 (1.2.3.4)                                    157.360ms

Automating it all with ifup/down

At this point, we have successfully created a virtual private network using SSH 4.3's tunnels. Can we automate this process with ifup/down? The answer is: yes! Machine A:

 iface tun0 inet static
        pre-up sleep 5
        address 10.0.0.100
        pointopoint 10.0.0.200
        netmask 255.255.255.0
        up arp -sD 10.0.0.200 eth0 pub

Machine B:

 iface tun0 inet static
        pre-up ssh -f -w 0:0 1.2.3.4 'ifdown tun0; ifup tun0'
        pre-up sleep 5
        address 10.0.0.200
        pointopoint 10.0.0.100
        netmask 255.255.255.0
        up route add -net 10.0.0.0 netmask 255.255.255.0 gw 10.0.0.200 tun0
        up route add 1.2.3.4 gw 192.168.0.1 eth0
        up route add default gw 10.0.0.1 tun0
        up route del default gw 192.168.0.1 eth0
        down route add default gw 192.168.0.1 eth0
        down route del default gw 10.0.0.1 tun0
        down route del -net 10.0.0.0 netmask 255.255.255.0 gw 10.0.0.200 tun0
        down route del 1.2.3.4 gw 192.168.0.1 eth0

These example /etc/network/interface snippets show how you would, on Machine B, simply have to execute: Machine B:

 sudo ifup tun0

And the system would automatically make the ssh connection, set up the tunnel, and turn on the VPN. Additionally, the ifdown command can be used to put the routes back to normal, or turn off the VPN. Note that the sleep commands in the snippet are there to allow ssh time to set the tunnel interface up, as it will not be instantaneous.

Where do I go from here?

There are many other possible ways to use SSH 4.3's tunnels besides creating a VPN to connect machine B to network A. For example, you could connect machine B to network A, and then route back on machine A to network B, creating a sort-of reverse VPN. Or you could connect machine B to network A, and then redirect traffic from network A to machine B to another system on network B. The possibilities are only limited by the amount of root access you have.