Linux 中虚拟专用网络的工作原理—第二部分

作者:David Morgan

本文的第一部分描述了理论。现在让我们继续 VPN mini-HOWTO,研究创建 VPN 的脚本,运行它,并解释我们所看到的内容。本 HOWTO(ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini/VPN, 文本版本,metalab.unc.edu/mdw/HOWTO/mini/VPN.html)是阅读本文的先决条件。该脚本由 Miquel van Smoorenburg 和 Ian Murdock 编写,位于 HOWTO 的 4.10 节。

该脚本在本地 VPN 服务器上运行。如果您进行双向配置,您可以安排从任一侧运行它,功能结果是等效的。我称之为本地/远程,Arpad Magosanyi 称之为主/从。为了工作目的,ssh 需要一个远程用户帐户才能登录。因此,首先创建并配置了一个远程用户“slave”,它不对应于任何人类用户(权限、密钥)。

脚本的核心体现了运行 pppdroute,如第 1 部分(题为“网络”的章节)所述。为了简化,这里是它。第 33 行是核心。

VPN HOWTO 脚本

line  1:  #! /bin/sh
line 19:  MYPPPIP=192.168.0.1
line 20:  TARGETIP=192.168.0.2
line 21:  TARGETNET=193.6.37.0

两台机器上的 PPPD

line 33:  /bin/pty-redir /usr/bin/ssh -o\
  'Batchmode yes' -t -l slave 206.170.217.204\
  /usr/local/bin/sudo /usr/sbin/pppd >/tmp/device
line 34:  TTYNAME='cat /tmp/device'
line 39:  /usr/sbin/pppd $TTYNAME\
${MYPPPIP}:${TARGETIP}
两台机器上的 ROUTE
line 45:  route add -net $TARGETNET gw $TARGETIP
line 46:  /usr/bin/ssh -o 'Batchmode\
yes' -l slave 206.170.217.204\
/usr/local/bin/sudo /home/slave/sshroute
我给这些行编号,然后删除了无关的行。为了可读性,我还替换了 shell 变量,并将它们的值更改为反映我的 Red Hat 5.1 服务器上的真实文件和路径名。忽略第 33 行中的 sudo —它只不过是一个命令过滤器/身份验证器,一种您设置的机制,允许某些命令运行,而禁止其他命令运行。它在这里是为了额外的安全性。它被设置为允许 pppd(HOWTO 第 4.9 节),因此从第 33 行中删除它不会影响操作。当您阅读第 33 行时,您应该看到
ssh -t -l slave 206.170.217.204 pppd
这表示,“以远程机器的用户帐户 'slave' 登录到远程机器并运行 pppd;使远程机器设置一个伪终端 (-t) 作为此 pppd 进程输出的目标。”
手动操作

请注意,在 HOWTO 的第 6 节“手动操作”中,与脚本不同,命令行中缺少 -t。当我第一次手动操作时,我没有成功地获得想要的“垃圾直接进入[我的]脸”,直到我添加了 -t。我通过使用以下机器 Internet 地址使其运行起来

local machine's public IP:      206.170.218.30
remote machine's public IP:     206.170.217.204

来自本地机器的屏幕截图是

[root@localhost /root]# ssh -t  -l slave  206.170.217.204
/usr/sbin/pppd
~˜}#A!}!}!} }2}!}$}"(}%}&} } öŒ}'}"}(}""q~~˜}#A!}
!}!} }2}!}$}"(}%}&} } öŒ}'}"}(}""q~~˜}#A!}!}!}
}2}!}$}"(}%}&} } öŒ}'}"}(}""q~~˜}#A!}!}!} }2}!}$}
"(}%}&} } öŒ}'}"}(}""q~~˜}#A!}!}!} }2}!}$}"
(}%}&} } öŒ}'}"}(}""q~~˜}#A!}!}!} }2}!}$}"(}%}&}
} öŒ}'}"}(}""q~~˜}#A!}!}!} }2}!}$}"(}%}&} } öŒ}'}
"}(}""q~~˜}#A!}!}!} }2}!}$}"(}%}&} } öŒ}'}"}
(}""q~~˜}#A!}!}!} }2}!}$}"(}%}&} } öŒ}'}"}
(}""q~~˜}#A!}!}!} }2}!}$}"(}%}&} } öŒ}'}"}
(}""q~~.
Connection to 206.170.217.204 closed.
[root@localhost /root]#
同时远程机器的日志条目是
Nov  7 20:17:19 localhost sshd[1403]:
log: Connection from 206.170.218.30 port 1023
Nov  7 20:17:21 localhost sshd[1403]:
log: RSA authentication for slave accepted.
Nov  7 20:17:22 localhost sshd[1405]:
log: executing remote command as user slave
Nov  7 20:17:22 localhost pppd[1405]:
pppd 2.3.3 started by slave, uid 507
Nov  7 20:17:22 localhost kernel:
registered device ppp1
Nov  7 20:17:22 localhost pppd[1405]:
Using interface ppp1
Nov  7 20:17:22 localhost pppd[1405]:
Connect: ppp1 <--> /dev/ttyp0
Nov  7 20:17:52 localhost pppd[1405]:
LCP: timeout sending Config-Requests
在下一步中,使用作者的 pty-redir 增强命令后,产生了
[root@localhost /root]# /bin/pty-redir
/usr/bin/ssh -t  -l slave  206.170.217.204  /usr/sbin/pppd
/dev/ttyp0[root@localhost /root]#
root@localhost /root]#
(垃圾去哪儿了?)和同时远程机器的日志条目
Nov  7 20:21:43 localhost sshd[1406]:
log: Connection from 206.170.218.30 port 1023
Nov  7 20:21:46 localhost sshd[1406]:
log: RSA authentication for slave accepted.
Nov  7 20:21:46 localhost sshd[1408]:
log: executing remote command as user slave
Nov  7 20:21:46 localhost pppd[1408]:
pppd 2.3.3 started by slave, uid 507
Nov  7 20:21:46 localhost pppd[1408]:
Using interface ppp1
Nov  7 20:21:46 localhost pppd[1408]:
Connect: ppp1 <--> /dev/ttyp0
Nov  7 20:22:16 localhost pppd[1408]:
LCP: timeout sending Config-Requests
到目前为止,它正在工作。跟踪日志,sshd 听到 ssh。sshd 同意运行 ssh 请求的命令(因为我预先配置了跨机器的密钥)。然后运行请求的 pppd 命令,它准备使用名为 ppp1 的接口,并将其与伪终端 /dev/ttyp0 关联。该过程仅在此处停止,因为从未从另一端运行 pppd;但是,远程端的所有内容都正确。当我们运行完整的脚本完成时,我们将看到该过程完成。

这两个调用之间有什么区别?在远程端,没有区别;日志是相同的。在本地端,在第二个调用中,整个 prior 命令字符串被馈送到 pty-redir 并在其控制下执行,这导致垃圾消失了,似乎是这样。实际上,它只是去了其他地方;pty-redir “重定向”了它。pty-redir 是 Mr. Magosanyi 编写的一个简短的 C 语言程序。它识别一个未使用的伪终端设备并打开它。然后,它强制标准输出(通常定向到控制台)改为伪终端。程序 (ssh) 将发送到控制台的任何内容都会被转移到伪终端设备。

不要将此伪终端与 -t 选项创建的伪终端混淆—它们位于不同的机器上。ssh -t 使远程端的 sshd 在那里创建一个伪终端,而 pty-redir 在本地端运行。按编号,这两个伪终端恰好都是 /dev/ttyp0,但这不会总是这样。本地伪终端体现在上面的屏幕输出中,远程伪终端体现在日志中。

虽然为了诊断目的而看到“垃圾在我们脸上”很好,但为了生产目的,最好将其隐藏起来。这就是编写 pty-redir 的原因。伪终端将证明作为传入 pppd 输出流的“接收容器”非常方便。我们可以将本地 pppd 启动到其中,以便创建所需的连接,而不必在我们的真实终端上更具侵入性地进行操作。

PPPD—一种不同类型的守护进程

这是对比 pppd 与 ssh 和其他守护进程建立的连接的地方。VPN 使用对称和非对称连接来实现“隧道”。ssh 是非对称的,并使用 TCP/IP 服务端口连接;pppd 是对称的,并使用设备端口连接。

PPP HOWTO 第 14 节“手动设置 PPP 连接”说明了 pppd 的要求。它必须在两台计算机上同时运行:两个输出流“在中间相遇”,以便它们可以协商连接设置。pppd 的输出流(如上所示)可能看起来像垃圾;但是,它是 pppd 的签名,对于另一个 pppd 副本来说非常有意义。(PPP HOWTO 第 9.5 节介绍了“ppp 垃圾”。)

“在中间相遇”意味着让相对的 pppd 在终端或端口设备 (/dev/ttyX) 上运行,这些设备连接,每个设备的输出作为另一个设备的输入进入。想法是将传入的数据流馈送到可识别的本地设备,然后将本地 pppd 启动到同一设备中。传出的流移动到传入的流从中出现的同一“管道”中。任何可用的终端或串行端口设备都可以。由于 Linux 提供了 /dev/ttypx 伪终端,它们是串行端口模拟器,因此它们也能很好地工作。这基本上就是 pty-redir 程序正在做的事情;它安排相对的 pppd 数据流在中间相遇。一旦发生这种情况,就会发生握手和协商,最终表现为可以使用 ifconfig 命令查看的 pppx 接口。

这突出了 pppd 与其他守护进程之间的一个重大区别:对称性。上个月,我们说过守护进程属于一对匹配的不同程序:一个是客户端,一个是服务器或守护进程。对于 pppd,没有区别,即没有客户端。pppd 程序与之对话的始终是另一个 pppd 副本自身,这是一种与自身对称的对话,而不是与不同程序非对称的对话。

另一个区别是,诸如 sshd 之类的其他守护进程通过涉及 TCP/IP 端口的 TCP/IP 连接进行对话。pppd 也通过连接进行对话并使用端口,但它使用自己的协议构建自己的连接类型,而不是 TCP/IP。它使用端口设备,而不是 TCP/IP 的编号服务端口(套接字)。

由于计算机可以多任务处理,TCP/IP 提供了在任何给定的计算机对上的多个进程对之间进行同时对话的功能。这些对话被分解为数据包。每个数据包都有一个标签(标头),其中包含目标计算机的 IP 地址和端口号。在目标计算机可能正在进行的(可能)许多对话中,端口号标识了此数据包所属的对话。一个对话由标头中的四个项目唯一确定:每一端的 IP 地址和每一端的 TCP 端口号。这些数据包看起来像图 1 中的那样(简化)。请参阅 http://oac3.hsc.uth.tmc.edu/staff/snewton/tcp-tutorial/ 上的“互联网协议简介”。

Workings of a Virtual Private Network in Linux—Part 2

图 1

在上面记录的对话中,我们在命令行上调用了 ssh,并将其定向到远程计算机 206.170.217.204。远程日志中的第一行显示

Nov  7 20:21:43 localhost sshd[1406]: log: Connection from 206.170.218.30 port 1023

ssh 向远程计算机上的 sshd 发送了一个数据包。sshd 被设置为“驻留”在端口 22,正如 ssh 所知。它发送的数据包看起来像图 2 中的那样。

Workings of a Virtual Private Network in Linux—Part 2

图 2

远程端口 22 上的 sshd 听到了这个,并用自己的数据包回答,将上面的目标和端口值从左向右交换。一个对话正在进行中。主要的业务顺序是加密密钥协商和身份验证,但在进入正题之前,看起来 sshd 告诉 ssh 将端口号从 22 更改为 1406(根据该日志条目,该条目由 sshd “签名”)。此后,如图 3 所示的大量数据包来回飞驰。

Workings of a Virtual Private Network in Linux—Part 2

图 3

某些服务器应用程序通常在定义的端口号上运行,这些端口号是公开已知的,以便客户端可以联系它们。这些被称为“众所周知的”或“特权”端口,范围从 0 到 1023。(请参阅 /etc/services。例如,端口 80 保留给 httpd,端口 21 保留给 ftpd。)一旦被联系,服务器通常会要求客户端切换端口号,以清除其众所周知的端口以进行其他传入对话。端口 22 是主要的 sshd 交换机。那里的操作员会尽快将您转移到另一条线路(“请稍候,我将转移您”),以便她可以处理其他来电。

现在应该清楚的是,pppd 永远无法使用 TCP/IP 服务端口,因为当 pppd 运行时,通常不存在 TCP/IP 连接。pppd 必须使用的连接是物理连接—电话线或直接串行电缆。TCP/IP 是传输层协议。pppd(基于 HDLC)在较低的数据链路通信层运行,pppd 数据包是 TCP/IP(或其他)数据包的载体或信封。由于这些根本差异,对“守护进程”和“端口”的重叠引用是不幸的。

运行完整的脚本

列表 1

现在让我们运行脚本来自动化并完成我们手动完成的操作。这是本地屏幕截图

[root@localhost /root]# /etc/rc.d/init.d/VPN start
setting up vpn
tty is /dev/ttyp1
[root@localhost /root]#

同时远程日志显示在列表 1 中,它显示 sshd 同意运行 ssh 请求的命令;这次 sshd 将对话放在端口 1022 上。请求的命令(请参阅 VPN HOWTO 脚本第 33 行)是 sudo,而不是 pppd。在远程机器中,sudo 反过来运行 pppd,它准备使用名为 ppp2 的接口,并将其与伪终端 /dev/ttyp1 关联。就在这个时候,有人在本地机器上运行 pppd(请参阅第 39 行)。两个 pppd 在中间相遇,本地 pppd(通过 ssh,然后 sshd)告诉远程 pppd 它希望为此连接的每一端使用哪些 IP 地址号。远程 pppd 同意,并将这些地址记录在日志中。此时,安全链接已双向就位。然后脚本继续运行 route。它通过地址通知每个 VPN 服务器,哪些额外的机器可以通过新连接到达,超出另一台服务器(即,另一台服务器所在的网络的地址)。为了响应脚本第 46 行,日志显示 sshd 在新的进程 ID 号 1439 下重新调用,这次是为了让 sudo 运行 sshroute,这是一个脚本(请参阅 HOWTO 第 4.10 节末尾),其中包含适当的 route 命令。

尘埃落定。安全链接现在已就位。我们如何查看和使用它?它采用新 PPP 接口的形式。通过运行 ifconfig 查看它。通过在路由表中将某些地址引用到它(已完成),然后将应用程序引用到这些地址来使用它。

列表 2

ifconfig 现在在每台机器上显示两个 ppp 接口,旧的和新的。本地机器上的屏幕截图如列表 2 所示。远程机器上的屏幕截图如列表 3 所示。本地机器的 ppp1 和远程机器的 ppp2 是同一连接的相对端,或彼此的接口。此连接是刚刚构建的连接。请注意接口号分配是特定于机器的,并且数字不必相同。本地和远程 ppp0 是机器各自的 ISP 连接,它们没有直接关系。

列表 3

为了引用另一个,每个 VPN 服务器现在可以选择 IP 地址。本地机器仍然可以使用其公共 Internet 地址 206.170.217.204 联系远程机器,但还可以选择调用它 192.168.0.2。例如,如果远程机器正在运行 Web 服务器,则本地机器上的浏览器将通过寻址到 http://206.170.217.204 或 http://192.168.0.2 来拉起完全相同的页面。可以使用任一地址 ping 远程机器。从表面上看,我们的两个 ppp 接口似乎是独立的和等效的。从逻辑上讲,它们是,您可以像使用它们一样使用它们;从物理上讲,它们不是。

信封内的信封—隧道

有什么区别?主要是,发送到 192.168.0.2 的数据包与发送到 206.170.217.204 的数据包的传输方式不同。相反,前者作为“货物”承载在后者内部。这就是为什么我在第 1 部分的网络图中将 PPP 连接描述为公共 ISP 连接的支流。这种安排称为隧道,因为一旦货运数据包到达其目的地,它们就会像从隧道中一样从其封闭的数据包中出现。它们作为功能性数据包而不是仅仅是被动数据被释放到目标网络上。

您可能已经注意到,为安全链接选择的 192.168.0.0 IP 地址属于“保留”范围,禁止在 Internet 上使用(PPP HOWTO 第 2 节),但我们正在 Internet 上使用这些地址。隧道是允许我们摆脱困境的原因。在 Internet 上时,带有这些地址的数据包仅作为数据传输。Internet 不需要根据这些地址路由它们—它们搭在合法寻址的数据包上。

隧道技术进入了所有 VPN 协议的讨论。有些在其名称中反映了这一点,例如 Microsoft 的 PPTP 或点对点隧道协议。隧道是 VPN 的一个特征;如果被隧道传输的数据也被加密,那么您就拥有了 VPN。

这是这里的另一个区别—加密。发送到和来自 192.168.0.2 的 Ping 数据包和网页会被加密和解密。发送到 206.170.217.204 的数据包,即使是同一个地方,也不会被加密和解密。但是您不会知道加密或隧道,因为它们是透明的。由于两者都存在,因此这是一个 VPN。

路由—完成图景

我发现 HOWTO 对路由的处理不够全面,可能超出了其预期范围。它最多只能通知每个 VPN 服务器关于对端网络上的工作站数量,但它没有教那些工作站相反的操作,并且它没有为一个网络上的工作站对另一个网络上的工作站的端到端感知提供支持。

主脚本提供的路由

route add -net 193.6.37.0 gw 192.168.0.2

在本地 VPN 服务器的路由表中放置一个条目,该条目表示“如果您处理任何地址以 193.6.37 开头的数据包,它们的交换中心是 192.168.0.2(远程 VPN 服务器),将它们发送给他。他会知道如何处理它们”,因为那是他所属网络的地址。

当我尝试从本地 VPN 服务器 ping 193.6.37 时,它失败了。虽然我有一条通往这些机器的路由,但问题是它们不知道返回我的反向路由。它们正确地收到了我的 ping 数据包,但它们无法回复回复数据包,因为它们的路由表从未听说过我—死信办公室。所以,我从未看到我的半成功的证据。

有两种解决方案。一种是在它们各自的路由表中添加一个条目来指明方向,不幸的是,这需要在这些多台机器上进行单独的调整。另一种解决方案需要在远程 VPN 服务器上进行一次更改,使用 pppd 的 proxyarp 选项。

ARP(地址解析协议)用于以太网环境。对于通过以太网进行通信的工作站来说,仅知道彼此的 IP 地址是不够的。它们只能在以太网数据包内部交换 TCP/IP 数据包。除非知道目标以太网(非 IP)地址,否则这些数据包无处可去。

机器维护一个目录,用于查找机器的以太网地址(给定其 IP 地址)。(Linux arp 命令会打印它。)如果您的列表中没有所需的目标 IP,您会自动向网络发出 ARP 广播。如果任何其他机器可以提供匹配的以太网地址,它将发送给您。

pppd proxyarp 命令在远程 VPN 服务器的目录中创建一个善意的谎言条目,该条目将本地 VPN 服务器的 TCP/IP 地址等同于远程 VPN 服务器的以太网地址。这解决了我的 ping 问题。如果远程工作站可以将回复发回远程 VPN 服务器,它们当然可以将它们剩余的路程发回我在本地 VPN 服务器。

另一个路由问题是本地和远程工作站彼此之间没有路由。解决方法是为每个本地工作站添加一个条目,指定本地或远程 VPN 服务器提供通往远程网络的路由。对于每个远程工作站,远程或本地服务器都提供路由。

对于本地工作站,命令是

route add -net 193.6.37.0 gw 192.168.0.1
or
route add -net 193.6.37.0 gw 192.168.0.2

对于远程工作站,

route add -net 193.6.35.0 gw 192.168.0.2
or
route add -net 193.6.35.0 gw 192.168.0.1
对于本地工作站,
route add -net 193.6.37.0 gw 192.168.0.1
route add -net 193.6.35.0 gw 192.168.0.2
or
route add -net 193.6.37.0 gw 192.168.0.2
route add -net 193.6.35.0 gw 192.168.0.1
(第二个命令仅在您运行 pppd 时调用 proxyarp 时才有效。)对于任一网络上的 Microsoft 机器,请将该网络的 VPN 服务器作为 TCP/IP 属性下的网关。

现在您是 VPN 专家了,所以您也知道 VPN 是毫无价值的,除非运行它的计算机以其他方式受到保护。例如,rsh 和 rlogin 最好禁用。ssh 旨在取代它们。如果它们仍然存在,您就有一扇门上了双重螺栓,而另一扇门大开。telnet 和 ftp 等其他服务也应关闭。您可以在 inetd.conf 文件中执行此操作。并且,应有目的地应用防火墙规则。尽管超出了本文的范围,但这些重要考虑因素需要提及。

资源

David Morgan 是洛杉矶的独立顾问,也是圣莫妮卡学院的计算机科学讲师。他于 1998 年开始认真对待 Linux。在等待 Linux 进入他的生活时,他获得了物理学和商业学位,在美国和平队担任教师,曾在 Rexon Business Machines、Nantucket Corporation、Computer Associates 和 Symantec Corporation 担任技术和产品管理职位。他骑自行车、背包旅行和烹饪。请将您的食谱和 VPN 经验发送给他。可以通过 dmorgan1@pacbell.net 联系到他,目前维护着 http://www.geocities.com/Yosemite/Gorge/3645/http://skydesign.hypermart.net/ 网站。

加载 Disqus 评论